blob: bec4f9aa48569866a2ab459adf979d4bcb58348f [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +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 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00007 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00008 */
9
Daniel Veillard34ce8be2002-03-18 19:37:11 +000010#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000011#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000012
Owen Taylor3473f882001-02-23 17:55:21 +000013#include <string.h>
14
15#ifdef HAVE_STDLIB_H
16#include <stdlib.h>
17#endif
18
19#include <libxml/xmlmemory.h>
20#include <libxml/hash.h>
21#include <libxml/valid.h>
22#include <libxml/parser.h>
23#include <libxml/parserInternals.h>
24#include <libxml/xmlerror.h>
25#include <libxml/list.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000026#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000027
Daniel Veillard4432df22003-09-28 18:58:27 +000028static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
29 int create);
30#ifdef LIBXML_VALID_ENABLED
31
Daniel Veillarde62d36c2001-05-15 08:53:16 +000032/* #define DEBUG_VALID_ALGO */
Daniel Veillard5acfd6b2002-09-18 16:29:02 +000033/* #define DEBUG_REGEXP_ALGO */
Daniel Veillarde62d36c2001-05-15 08:53:16 +000034
Daniel Veillarda646cfd2002-09-17 21:50:03 +000035#define TODO \
36 xmlGenericError(xmlGenericErrorContext, \
37 "Unimplemented block at %s:%d\n", \
38 __FILE__, __LINE__);
Owen Taylor3473f882001-02-23 17:55:21 +000039
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000040/************************************************************************
41 * *
42 * Error handling routines *
43 * *
44 ************************************************************************/
45
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000046/**
Daniel Veillardce9457f2003-10-05 21:33:18 +000047 * xmlVErrMemory:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000048 * @ctxt: an XML validation parser context
49 * @extra: extra informations
50 *
51 * Handle an out of memory error
52 */
53static void
Daniel Veillardce9457f2003-10-05 21:33:18 +000054xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000055{
Daniel Veillard659e71e2003-10-10 14:10:40 +000056 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +000057 xmlGenericErrorFunc channel = NULL;
58 xmlParserCtxtPtr pctxt = NULL;
59 void *data = NULL;
60
61 if (ctxt != NULL) {
62 channel = ctxt->error;
63 data = ctxt->userData;
64 pctxt = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +000065 schannel = ctxt->serror;
Daniel Veillardbb5abab2003-10-03 22:21:51 +000066 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000067 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +000068 __xmlRaiseError(schannel, channel, data,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000069 pctxt, NULL, XML_FROM_DTD, XML_ERR_NO_MEMORY,
70 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
71 "Memory allocation failed : %s\n", extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000072 else
Daniel Veillard659e71e2003-10-10 14:10:40 +000073 __xmlRaiseError(schannel, channel, data,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000074 pctxt, NULL, XML_FROM_DTD, XML_ERR_NO_MEMORY,
75 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
76 "Memory allocation failed\n");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000077}
78
79/**
80 * xmlErrValid:
81 * @ctxt: an XML validation parser context
Daniel Veillardbb5abab2003-10-03 22:21:51 +000082 * @error: the error number
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000083 * @extra: extra informations
84 *
85 * Handle a validation error
86 */
87static void
88xmlErrValid(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlParserErrors error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000089 const char *msg, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000090{
Daniel Veillard659e71e2003-10-10 14:10:40 +000091 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +000092 xmlGenericErrorFunc channel = NULL;
93 xmlParserCtxtPtr pctxt = NULL;
94 void *data = NULL;
95
96 if (ctxt != NULL) {
97 channel = ctxt->error;
Daniel Veillard659e71e2003-10-10 14:10:40 +000098 schannel = ctxt->serror;
Daniel Veillardbb5abab2003-10-03 22:21:51 +000099 data = ctxt->userData;
100 pctxt = ctxt->userData;
101 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000102 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000103 __xmlRaiseError(schannel, channel, data,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000104 pctxt, NULL, XML_FROM_DTD, error,
105 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
106 msg, extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000107 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000108 __xmlRaiseError(schannel, channel, data,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000109 pctxt, NULL, XML_FROM_DTD, error,
110 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
111 msg);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000112}
113
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000114/**
115 * xmlErrValidNodeNr:
116 * @ctxt: an XML validation parser context
117 * @node: the node raising the error
118 * @error: the error number
119 * @str1: extra informations
120 * @int2: extra informations
121 * @str3: extra informations
122 *
123 * Handle a validation error, provide contextual informations
124 */
125static void
126xmlErrValidNodeNr(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
127 xmlNodePtr node, xmlParserErrors error,
128 const char *msg, const xmlChar * str1,
129 int int2, const xmlChar * str3)
130{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000131 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000132 xmlGenericErrorFunc channel = NULL;
133 xmlParserCtxtPtr pctxt = NULL;
134 void *data = NULL;
135
136 if (ctxt != NULL) {
137 channel = ctxt->error;
138 data = ctxt->userData;
139 pctxt = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000140 pctxt = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000141 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000142 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_DTD, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000143 XML_ERR_ERROR, NULL, 0,
144 (const char *) str1,
145 (const char *) str3,
146 NULL, int2, 0, msg, str1, int2, str3);
147}
148/**
149 * xmlErrValidNode:
150 * @ctxt: an XML validation parser context
151 * @node: the node raising the error
152 * @error: the error number
153 * @str1: extra informations
154 * @str2: extra informations
155 * @str3: extra informations
156 *
157 * Handle a validation error, provide contextual informations
158 */
159static void
160xmlErrValidNode(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
161 xmlNodePtr node, xmlParserErrors error,
162 const char *msg, const xmlChar * str1,
163 const xmlChar * str2, const xmlChar * str3)
164{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000165 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000166 xmlGenericErrorFunc channel = NULL;
167 xmlParserCtxtPtr pctxt = NULL;
168 void *data = NULL;
169
170 if (ctxt != NULL) {
171 channel = ctxt->error;
172 data = ctxt->userData;
173 pctxt = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000174 pctxt = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000175 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000176 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_DTD, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000177 XML_ERR_ERROR, NULL, 0,
178 (const char *) str1,
179 (const char *) str1,
180 (const char *) str3, 0, 0, msg, str1, str2, str3);
181}
182/**
183 * xmlErrValidWarning:
184 * @ctxt: an XML validation parser context
185 * @node: the node raising the error
186 * @error: the error number
187 * @str1: extra informations
188 * @str2: extra informations
189 * @str3: extra informations
190 *
191 * Handle a validation error, provide contextual informations
192 */
193static void
194xmlErrValidWarning(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
195 xmlNodePtr node, xmlParserErrors error,
196 const char *msg, const xmlChar * str1,
197 const xmlChar * str2, const xmlChar * str3)
198{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000199 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000200 xmlGenericErrorFunc channel = NULL;
201 xmlParserCtxtPtr pctxt = NULL;
202 void *data = NULL;
203
204 if (ctxt != NULL) {
205 channel = ctxt->error;
206 data = ctxt->userData;
207 pctxt = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000208 pctxt = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000209 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000210 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_DTD, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000211 XML_ERR_WARNING, NULL, 0,
212 (const char *) str1,
213 (const char *) str1,
214 (const char *) str3, 0, 0, msg, str1, str2, str3);
215}
216
217
Daniel Veillardea7751d2002-12-20 00:16:24 +0000218
219#ifdef LIBXML_REGEXP_ENABLED
220/*
221 * If regexp are enabled we can do continuous validation without the
222 * need of a tree to validate the content model. this is done in each
223 * callbacks.
224 * Each xmlValidState represent the validation state associated to the
225 * set of nodes currently open from the document root to the current element.
226 */
227
228
229typedef struct _xmlValidState {
230 xmlElementPtr elemDecl; /* pointer to the content model */
231 xmlNodePtr node; /* pointer to the current node */
232 xmlRegExecCtxtPtr exec; /* regexp runtime */
233} _xmlValidState;
234
235
236static int
237vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000238 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000239 ctxt->vstateMax = 10;
240 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
241 sizeof(ctxt->vstateTab[0]));
242 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000243 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000244 return(-1);
245 }
246 }
247
248 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000249 xmlValidState *tmp;
250
251 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
252 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
253 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000254 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000255 return(-1);
256 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000257 ctxt->vstateMax *= 2;
258 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000259 }
260 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
261 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
262 ctxt->vstateTab[ctxt->vstateNr].node = node;
263 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
264 if (elemDecl->contModel == NULL)
265 xmlValidBuildContentModel(ctxt, elemDecl);
266 if (elemDecl->contModel != NULL) {
267 ctxt->vstateTab[ctxt->vstateNr].exec =
268 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
269 } else {
270 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000271 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
272 XML_ERR_INTERNAL_ERROR,
273 "Failed to build content model regexp for %s\n",
274 node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000275 }
276 }
277 return(ctxt->vstateNr++);
278}
279
280static int
281vstateVPop(xmlValidCtxtPtr ctxt) {
282 xmlElementPtr elemDecl;
283
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000284 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000285 ctxt->vstateNr--;
286 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
287 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
288 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
289 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
290 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
291 }
292 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
293 if (ctxt->vstateNr >= 1)
294 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
295 else
296 ctxt->vstate = NULL;
297 return(ctxt->vstateNr);
298}
299
300#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000301/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000302 * If regexp are not enabled, it uses a home made algorithm less
303 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000304 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000305 * only restriction is on the deepness of the tree limited by the
306 * size of the occurs bitfield
307 *
308 * this is the content of a saved state for rollbacks
309 */
310
311#define ROLLBACK_OR 0
312#define ROLLBACK_PARENT 1
313
Daniel Veillardb44025c2001-10-11 22:55:55 +0000314typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000315 xmlElementContentPtr cont; /* pointer to the content model subtree */
316 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000317 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000318 unsigned char depth; /* current depth in the overall tree */
319 unsigned char state; /* ROLLBACK_XXX */
320} _xmlValidState;
321
Daniel Veillardfc57b412002-04-29 15:50:14 +0000322#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000323#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
324#define CONT ctxt->vstate->cont
325#define NODE ctxt->vstate->node
326#define DEPTH ctxt->vstate->depth
327#define OCCURS ctxt->vstate->occurs
328#define STATE ctxt->vstate->state
329
Daniel Veillard5344c602001-12-31 16:37:34 +0000330#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
331#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000332
Daniel Veillard5344c602001-12-31 16:37:34 +0000333#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
334#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000335
336static int
337vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
338 xmlNodePtr node, unsigned char depth, long occurs,
339 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000340 int i = ctxt->vstateNr - 1;
341
Daniel Veillard940492d2002-04-15 10:15:25 +0000342 if (ctxt->vstateNr > MAX_RECURSE) {
343 return(-1);
344 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000345 if (ctxt->vstateTab == NULL) {
346 ctxt->vstateMax = 8;
347 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
348 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
349 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000350 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000351 return(-1);
352 }
353 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000354 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000355 xmlValidState *tmp;
356
357 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
358 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
359 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000360 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000361 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000362 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000363 ctxt->vstateMax *= 2;
364 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000365 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000366 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000367 /*
368 * Don't push on the stack a state already here
369 */
370 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
371 (ctxt->vstateTab[i].node == node) &&
372 (ctxt->vstateTab[i].depth == depth) &&
373 (ctxt->vstateTab[i].occurs == occurs) &&
374 (ctxt->vstateTab[i].state == state))
375 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000376 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
377 ctxt->vstateTab[ctxt->vstateNr].node = node;
378 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
379 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
380 ctxt->vstateTab[ctxt->vstateNr].state = state;
381 return(ctxt->vstateNr++);
382}
383
384static int
385vstateVPop(xmlValidCtxtPtr ctxt) {
386 if (ctxt->vstateNr <= 1) return(-1);
387 ctxt->vstateNr--;
388 ctxt->vstate = &ctxt->vstateTab[0];
389 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
390 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
391 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
392 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
393 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
394 return(ctxt->vstateNr);
395}
396
Daniel Veillard118aed72002-09-24 14:13:13 +0000397#endif /* LIBXML_REGEXP_ENABLED */
398
Daniel Veillard1c732d22002-11-30 11:22:59 +0000399static int
400nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
401{
402 if (ctxt->nodeMax <= 0) {
403 ctxt->nodeMax = 4;
404 ctxt->nodeTab =
405 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
406 sizeof(ctxt->nodeTab[0]));
407 if (ctxt->nodeTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000408 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000409 ctxt->nodeMax = 0;
410 return (0);
411 }
412 }
413 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000414 xmlNodePtr *tmp;
415 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
416 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
417 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000418 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000419 return (0);
420 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000421 ctxt->nodeMax *= 2;
422 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000423 }
424 ctxt->nodeTab[ctxt->nodeNr] = value;
425 ctxt->node = value;
426 return (ctxt->nodeNr++);
427}
428static xmlNodePtr
429nodeVPop(xmlValidCtxtPtr ctxt)
430{
431 xmlNodePtr ret;
432
433 if (ctxt->nodeNr <= 0)
434 return (0);
435 ctxt->nodeNr--;
436 if (ctxt->nodeNr > 0)
437 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
438 else
439 ctxt->node = NULL;
440 ret = ctxt->nodeTab[ctxt->nodeNr];
441 ctxt->nodeTab[ctxt->nodeNr] = 0;
442 return (ret);
443}
Owen Taylor3473f882001-02-23 17:55:21 +0000444
Owen Taylor3473f882001-02-23 17:55:21 +0000445#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000446static void
447xmlValidPrintNode(xmlNodePtr cur) {
448 if (cur == NULL) {
449 xmlGenericError(xmlGenericErrorContext, "null");
450 return;
451 }
452 switch (cur->type) {
453 case XML_ELEMENT_NODE:
454 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
455 break;
456 case XML_TEXT_NODE:
457 xmlGenericError(xmlGenericErrorContext, "text ");
458 break;
459 case XML_CDATA_SECTION_NODE:
460 xmlGenericError(xmlGenericErrorContext, "cdata ");
461 break;
462 case XML_ENTITY_REF_NODE:
463 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
464 break;
465 case XML_PI_NODE:
466 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
467 break;
468 case XML_COMMENT_NODE:
469 xmlGenericError(xmlGenericErrorContext, "comment ");
470 break;
471 case XML_ATTRIBUTE_NODE:
472 xmlGenericError(xmlGenericErrorContext, "?attr? ");
473 break;
474 case XML_ENTITY_NODE:
475 xmlGenericError(xmlGenericErrorContext, "?ent? ");
476 break;
477 case XML_DOCUMENT_NODE:
478 xmlGenericError(xmlGenericErrorContext, "?doc? ");
479 break;
480 case XML_DOCUMENT_TYPE_NODE:
481 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
482 break;
483 case XML_DOCUMENT_FRAG_NODE:
484 xmlGenericError(xmlGenericErrorContext, "?frag? ");
485 break;
486 case XML_NOTATION_NODE:
487 xmlGenericError(xmlGenericErrorContext, "?nota? ");
488 break;
489 case XML_HTML_DOCUMENT_NODE:
490 xmlGenericError(xmlGenericErrorContext, "?html? ");
491 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000492#ifdef LIBXML_DOCB_ENABLED
493 case XML_DOCB_DOCUMENT_NODE:
494 xmlGenericError(xmlGenericErrorContext, "?docb? ");
495 break;
496#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000497 case XML_DTD_NODE:
498 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
499 break;
500 case XML_ELEMENT_DECL:
501 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
502 break;
503 case XML_ATTRIBUTE_DECL:
504 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
505 break;
506 case XML_ENTITY_DECL:
507 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
508 break;
509 case XML_NAMESPACE_DECL:
510 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
511 break;
512 case XML_XINCLUDE_START:
513 xmlGenericError(xmlGenericErrorContext, "incstart ");
514 break;
515 case XML_XINCLUDE_END:
516 xmlGenericError(xmlGenericErrorContext, "incend ");
517 break;
518 }
519}
520
521static void
522xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000523 if (cur == NULL)
524 xmlGenericError(xmlGenericErrorContext, "null ");
525 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000526 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000527 cur = cur->next;
528 }
529}
530
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000531static void
532xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000533 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000534
535 expr[0] = 0;
536 xmlGenericError(xmlGenericErrorContext, "valid: ");
537 xmlValidPrintNodeList(cur);
538 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000539 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000540 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
541}
542
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000543static void
544xmlValidDebugState(xmlValidStatePtr state) {
545 xmlGenericError(xmlGenericErrorContext, "(");
546 if (state->cont == NULL)
547 xmlGenericError(xmlGenericErrorContext, "null,");
548 else
549 switch (state->cont->type) {
550 case XML_ELEMENT_CONTENT_PCDATA:
551 xmlGenericError(xmlGenericErrorContext, "pcdata,");
552 break;
553 case XML_ELEMENT_CONTENT_ELEMENT:
554 xmlGenericError(xmlGenericErrorContext, "%s,",
555 state->cont->name);
556 break;
557 case XML_ELEMENT_CONTENT_SEQ:
558 xmlGenericError(xmlGenericErrorContext, "seq,");
559 break;
560 case XML_ELEMENT_CONTENT_OR:
561 xmlGenericError(xmlGenericErrorContext, "or,");
562 break;
563 }
564 xmlValidPrintNode(state->node);
565 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
566 state->depth, state->occurs, state->state);
567}
568
569static void
570xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
571 int i, j;
572
573 xmlGenericError(xmlGenericErrorContext, "state: ");
574 xmlValidDebugState(ctxt->vstate);
575 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
576 ctxt->vstateNr - 1);
577 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
578 xmlValidDebugState(&ctxt->vstateTab[j]);
579 xmlGenericError(xmlGenericErrorContext, "\n");
580}
581
582/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000583#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000584 *****/
585
586#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000587#define DEBUG_VALID_MSG(m) \
588 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
589
Owen Taylor3473f882001-02-23 17:55:21 +0000590#else
591#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000592#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000593#endif
594
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000595/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000596
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000597
Owen Taylor3473f882001-02-23 17:55:21 +0000598#define CHECK_DTD \
599 if (doc == NULL) return(0); \
600 else if ((doc->intSubset == NULL) && \
601 (doc->extSubset == NULL)) return(0)
602
Owen Taylor3473f882001-02-23 17:55:21 +0000603xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
604
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000605#ifdef LIBXML_REGEXP_ENABLED
606
607/************************************************************************
608 * *
609 * Content model validation based on the regexps *
610 * *
611 ************************************************************************/
612
613/**
614 * xmlValidBuildAContentModel:
615 * @content: the content model
616 * @ctxt: the schema parser context
617 * @name: the element name whose content is being built
618 *
619 * Generate the automata sequence needed for that type
620 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000621 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000622 */
623static int
624xmlValidBuildAContentModel(xmlElementContentPtr content,
625 xmlValidCtxtPtr ctxt,
626 const xmlChar *name) {
627 if (content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000628 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
629 "Found NULL content in content model of %s\n",
630 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000631 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000632 }
633 switch (content->type) {
634 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000635 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
636 "Found PCDATA in content model of %s\n",
637 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000638 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000639 break;
640 case XML_ELEMENT_CONTENT_ELEMENT: {
641 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000642 xmlChar fn[50];
643 xmlChar *fullname;
644
645 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
646 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000647 xmlVErrMemory(ctxt, "Building content model");
Daniel Veillardc00cda82003-04-07 10:22:39 +0000648 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000649 }
650
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000651 switch (content->ocur) {
652 case XML_ELEMENT_CONTENT_ONCE:
653 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000654 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000655 break;
656 case XML_ELEMENT_CONTENT_OPT:
657 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000658 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000659 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
660 break;
661 case XML_ELEMENT_CONTENT_PLUS:
662 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000663 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000664 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000665 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000666 break;
667 case XML_ELEMENT_CONTENT_MULT:
668 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000669 ctxt->state, fullname, NULL);
Daniel Veillard57e79b32003-02-04 15:33:12 +0000670 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
671 NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000672 break;
673 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000674 if ((fullname != fn) && (fullname != content->name))
675 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000676 break;
677 }
678 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000679 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000680 xmlElementContentOccur ocur;
681
682 /*
683 * Simply iterate over the content
684 */
685 oldstate = ctxt->state;
686 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000687 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
688 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
689 oldstate = ctxt->state;
690 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000691 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000692 xmlValidBuildAContentModel(content->c1, ctxt, name);
693 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000694 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
695 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
696 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000697 oldend = ctxt->state;
698 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000699 switch (ocur) {
700 case XML_ELEMENT_CONTENT_ONCE:
701 break;
702 case XML_ELEMENT_CONTENT_OPT:
703 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
704 break;
705 case XML_ELEMENT_CONTENT_MULT:
706 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000707 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000708 break;
709 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000710 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000711 break;
712 }
713 break;
714 }
715 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000716 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000717 xmlElementContentOccur ocur;
718
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000719 ocur = content->ocur;
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000720 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
721 (ocur == XML_ELEMENT_CONTENT_MULT)) {
722 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
723 ctxt->state, NULL);
724 }
725 oldstate = ctxt->state;
726 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000727
728 /*
729 * iterate over the subtypes and remerge the end with an
730 * epsilon transition
731 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000732 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000733 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000734 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000735 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000736 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000737 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
738 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000739 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000740 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000741 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
742 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000743 switch (ocur) {
744 case XML_ELEMENT_CONTENT_ONCE:
745 break;
746 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000747 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000748 break;
749 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000750 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
751 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000752 break;
753 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000754 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000755 break;
756 }
757 break;
758 }
759 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000760 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
761 "ContentModel broken for element %s\n",
762 (const char *) name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000763 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000764 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000765 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000766}
767/**
768 * xmlValidBuildContentModel:
769 * @ctxt: a validation context
770 * @elem: an element declaration node
771 *
772 * (Re)Build the automata associated to the content model of this
773 * element
774 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000775 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000776 */
777int
778xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000779
780 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000781 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000782 if (elem->type != XML_ELEMENT_DECL)
783 return(0);
784 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
785 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000786 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000787 if (elem->contModel != NULL) {
788 if (!xmlRegexpIsDeterminist(elem->contModel)) {
789 ctxt->valid = 0;
790 return(0);
791 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000792 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000793 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000794
795 ctxt->am = xmlNewAutomata();
796 if (ctxt->am == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000797 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
798 XML_ERR_INTERNAL_ERROR,
799 "Cannot create automata for element %s\n",
800 elem->name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000801 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000802 }
William M. Brack78637da2003-07-31 14:47:38 +0000803 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000804 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
805 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000806 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000807 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000808 char expr[5000];
809 expr[0] = 0;
810 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000811 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
812 XML_DTD_CONTENT_NOT_DETERMINIST,
813 "Content model of %s is not determinist: %s\n",
814 elem->name, BAD_CAST expr, NULL);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000815#ifdef DEBUG_REGEXP_ALGO
816 xmlRegexpPrint(stderr, elem->contModel);
817#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000818 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000819 ctxt->state = NULL;
820 xmlFreeAutomata(ctxt->am);
821 ctxt->am = NULL;
822 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000823 }
824 ctxt->state = NULL;
825 xmlFreeAutomata(ctxt->am);
826 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000827 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000828}
829
830#endif /* LIBXML_REGEXP_ENABLED */
831
Owen Taylor3473f882001-02-23 17:55:21 +0000832/****************************************************************
833 * *
834 * Util functions for data allocation/deallocation *
835 * *
836 ****************************************************************/
837
838/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000839 * xmlNewValidCtxt:
840 *
841 * Allocate a validation context structure.
842 *
843 * Returns NULL if not, otherwise the new validation context structure
844 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000845xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000846 xmlValidCtxtPtr ret;
847
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000848 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000849 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000850 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000851 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000852
853 (void) memset(ret, 0, sizeof (xmlValidCtxt));
854
855 return (ret);
856}
857
858/**
859 * xmlFreeValidCtxt:
860 * @cur: the validation context to free
861 *
862 * Free a validation context structure.
863 */
864void
865xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
866 xmlFree(cur);
867}
868
Daniel Veillard4432df22003-09-28 18:58:27 +0000869#endif /* LIBXML_VALID_ENABLED */
870
Daniel Veillarda37aab82003-06-09 09:10:36 +0000871/**
Owen Taylor3473f882001-02-23 17:55:21 +0000872 * xmlNewElementContent:
873 * @name: the subelement name or NULL
874 * @type: the type of element content decl
875 *
876 * Allocate an element content structure.
877 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000878 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000879 */
880xmlElementContentPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000881xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000882 xmlElementContentPtr ret;
883
884 switch(type) {
885 case XML_ELEMENT_CONTENT_ELEMENT:
886 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000887 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
888 "xmlNewElementContent : name == NULL !\n",
889 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000890 }
891 break;
892 case XML_ELEMENT_CONTENT_PCDATA:
893 case XML_ELEMENT_CONTENT_SEQ:
894 case XML_ELEMENT_CONTENT_OR:
895 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000896 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
897 "xmlNewElementContent : name != NULL !\n",
898 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000899 }
900 break;
901 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000902 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
903 "Internal: ELEMENT content corrupted invalid type\n",
904 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000905 return(NULL);
906 }
907 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
908 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000909 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000910 return(NULL);
911 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000912 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000913 ret->type = type;
914 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000915 if (name != NULL) {
916 xmlChar *prefix = NULL;
917 ret->name = xmlSplitQName2(name, &prefix);
918 if (ret->name == NULL)
919 ret->name = xmlStrdup(name);
920 ret->prefix = prefix;
921 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000922 ret->name = NULL;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000923 ret->prefix = NULL;
924 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000925 ret->c1 = ret->c2 = ret->parent = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000926 return(ret);
927}
928
929/**
930 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000931 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +0000932 *
933 * Build a copy of an element content description.
934 *
935 * Returns the new xmlElementContentPtr or NULL in case of error.
936 */
937xmlElementContentPtr
938xmlCopyElementContent(xmlElementContentPtr cur) {
939 xmlElementContentPtr ret;
940
941 if (cur == NULL) return(NULL);
942 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
943 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000944 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000945 return(NULL);
946 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000947 if (cur->prefix != NULL)
948 ret->prefix = xmlStrdup(cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000949 ret->ocur = cur->ocur;
950 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000951 if (ret->c1 != NULL)
952 ret->c1->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000953 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000954 if (ret->c2 != NULL)
955 ret->c2->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000956 return(ret);
957}
958
959/**
960 * xmlFreeElementContent:
961 * @cur: the element content tree to free
962 *
963 * Free an element content structure. This is a recursive call !
964 */
965void
966xmlFreeElementContent(xmlElementContentPtr cur) {
967 if (cur == NULL) return;
968 switch (cur->type) {
969 case XML_ELEMENT_CONTENT_PCDATA:
970 case XML_ELEMENT_CONTENT_ELEMENT:
971 case XML_ELEMENT_CONTENT_SEQ:
972 case XML_ELEMENT_CONTENT_OR:
973 break;
974 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000975 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
976 "Internal: ELEMENT content corrupted invalid type\n",
977 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000978 return;
979 }
980 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
981 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
982 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000983 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000984 xmlFree(cur);
985}
986
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000987#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000988/**
989 * xmlDumpElementContent:
990 * @buf: An XML buffer
991 * @content: An element table
992 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
993 *
994 * This will dump the content of the element table as an XML DTD definition
995 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000996static void
Owen Taylor3473f882001-02-23 17:55:21 +0000997xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
998 if (content == NULL) return;
999
1000 if (glob) xmlBufferWriteChar(buf, "(");
1001 switch (content->type) {
1002 case XML_ELEMENT_CONTENT_PCDATA:
1003 xmlBufferWriteChar(buf, "#PCDATA");
1004 break;
1005 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001006 if (content->prefix != NULL) {
1007 xmlBufferWriteCHAR(buf, content->prefix);
1008 xmlBufferWriteChar(buf, ":");
1009 }
Owen Taylor3473f882001-02-23 17:55:21 +00001010 xmlBufferWriteCHAR(buf, content->name);
1011 break;
1012 case XML_ELEMENT_CONTENT_SEQ:
1013 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1014 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1015 xmlDumpElementContent(buf, content->c1, 1);
1016 else
1017 xmlDumpElementContent(buf, content->c1, 0);
1018 xmlBufferWriteChar(buf, " , ");
1019 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
1020 xmlDumpElementContent(buf, content->c2, 1);
1021 else
1022 xmlDumpElementContent(buf, content->c2, 0);
1023 break;
1024 case XML_ELEMENT_CONTENT_OR:
1025 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1026 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1027 xmlDumpElementContent(buf, content->c1, 1);
1028 else
1029 xmlDumpElementContent(buf, content->c1, 0);
1030 xmlBufferWriteChar(buf, " | ");
1031 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
1032 xmlDumpElementContent(buf, content->c2, 1);
1033 else
1034 xmlDumpElementContent(buf, content->c2, 0);
1035 break;
1036 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001037 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1038 "Internal: ELEMENT content corrupted invalid type\n",
1039 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001040 }
1041 if (glob)
1042 xmlBufferWriteChar(buf, ")");
1043 switch (content->ocur) {
1044 case XML_ELEMENT_CONTENT_ONCE:
1045 break;
1046 case XML_ELEMENT_CONTENT_OPT:
1047 xmlBufferWriteChar(buf, "?");
1048 break;
1049 case XML_ELEMENT_CONTENT_MULT:
1050 xmlBufferWriteChar(buf, "*");
1051 break;
1052 case XML_ELEMENT_CONTENT_PLUS:
1053 xmlBufferWriteChar(buf, "+");
1054 break;
1055 }
1056}
1057
1058/**
1059 * xmlSprintfElementContent:
1060 * @buf: an output buffer
1061 * @content: An element table
1062 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1063 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001064 * Deprecated, unsafe, use xmlSnprintfElementContent
1065 */
1066void
1067xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1068 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1069 int glob ATTRIBUTE_UNUSED) {
1070}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001071#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001072
1073/**
1074 * xmlSnprintfElementContent:
1075 * @buf: an output buffer
1076 * @size: the buffer size
1077 * @content: An element table
1078 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1079 *
Owen Taylor3473f882001-02-23 17:55:21 +00001080 * This will dump the content of the element content definition
1081 * Intended just for the debug routine
1082 */
1083void
Daniel Veillardd3d06722001-08-15 12:06:36 +00001084xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int glob) {
1085 int len;
1086
Owen Taylor3473f882001-02-23 17:55:21 +00001087 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001088 len = strlen(buf);
1089 if (size - len < 50) {
1090 if ((size - len > 4) && (buf[len - 1] != '.'))
1091 strcat(buf, " ...");
1092 return;
1093 }
Owen Taylor3473f882001-02-23 17:55:21 +00001094 if (glob) strcat(buf, "(");
1095 switch (content->type) {
1096 case XML_ELEMENT_CONTENT_PCDATA:
1097 strcat(buf, "#PCDATA");
1098 break;
1099 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001100 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001101 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001102 strcat(buf, " ...");
1103 return;
1104 }
1105 strcat(buf, (char *) content->prefix);
1106 strcat(buf, ":");
1107 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001108 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001109 strcat(buf, " ...");
1110 return;
1111 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001112 if (content->name != NULL)
1113 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001114 break;
1115 case XML_ELEMENT_CONTENT_SEQ:
1116 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1117 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001118 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001119 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001120 xmlSnprintfElementContent(buf, size, content->c1, 0);
1121 len = strlen(buf);
1122 if (size - len < 50) {
1123 if ((size - len > 4) && (buf[len - 1] != '.'))
1124 strcat(buf, " ...");
1125 return;
1126 }
Owen Taylor3473f882001-02-23 17:55:21 +00001127 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001128 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1129 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1130 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001131 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001132 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001133 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001134 break;
1135 case XML_ELEMENT_CONTENT_OR:
1136 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1137 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001138 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001139 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001140 xmlSnprintfElementContent(buf, size, content->c1, 0);
1141 len = strlen(buf);
1142 if (size - len < 50) {
1143 if ((size - len > 4) && (buf[len - 1] != '.'))
1144 strcat(buf, " ...");
1145 return;
1146 }
Owen Taylor3473f882001-02-23 17:55:21 +00001147 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001148 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1149 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1150 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001151 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001152 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001153 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001154 break;
1155 }
1156 if (glob)
1157 strcat(buf, ")");
1158 switch (content->ocur) {
1159 case XML_ELEMENT_CONTENT_ONCE:
1160 break;
1161 case XML_ELEMENT_CONTENT_OPT:
1162 strcat(buf, "?");
1163 break;
1164 case XML_ELEMENT_CONTENT_MULT:
1165 strcat(buf, "*");
1166 break;
1167 case XML_ELEMENT_CONTENT_PLUS:
1168 strcat(buf, "+");
1169 break;
1170 }
1171}
1172
1173/****************************************************************
1174 * *
1175 * Registration of DTD declarations *
1176 * *
1177 ****************************************************************/
1178
1179/**
1180 * xmlCreateElementTable:
1181 *
1182 * create and initialize an empty element hash table.
1183 *
1184 * Returns the xmlElementTablePtr just created or NULL in case of error.
1185 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001186static xmlElementTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001187xmlCreateElementTable(void) {
1188 return(xmlHashCreate(0));
1189}
1190
1191/**
1192 * xmlFreeElement:
1193 * @elem: An element
1194 *
1195 * Deallocate the memory used by an element definition
1196 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001197static void
Owen Taylor3473f882001-02-23 17:55:21 +00001198xmlFreeElement(xmlElementPtr elem) {
1199 if (elem == NULL) return;
1200 xmlUnlinkNode((xmlNodePtr) elem);
1201 xmlFreeElementContent(elem->content);
1202 if (elem->name != NULL)
1203 xmlFree((xmlChar *) elem->name);
1204 if (elem->prefix != NULL)
1205 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001206#ifdef LIBXML_REGEXP_ENABLED
1207 if (elem->contModel != NULL)
1208 xmlRegFreeRegexp(elem->contModel);
1209#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001210 xmlFree(elem);
1211}
1212
1213
1214/**
1215 * xmlAddElementDecl:
1216 * @ctxt: the validation context
1217 * @dtd: pointer to the DTD
1218 * @name: the entity name
1219 * @type: the element type
1220 * @content: the element content tree or NULL
1221 *
1222 * Register a new element declaration
1223 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001224 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001225 */
1226xmlElementPtr
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001227xmlAddElementDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1228 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001229 xmlElementTypeVal type,
1230 xmlElementContentPtr content) {
1231 xmlElementPtr ret;
1232 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001233 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001234 xmlChar *ns, *uqname;
1235
1236 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001237 return(NULL);
1238 }
1239 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001240 return(NULL);
1241 }
1242 switch (type) {
1243 case XML_ELEMENT_TYPE_EMPTY:
1244 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001245 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1246 "xmlAddElementDecl: content != NULL for EMPTY\n",
1247 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001248 return(NULL);
1249 }
1250 break;
1251 case XML_ELEMENT_TYPE_ANY:
1252 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001253 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1254 "xmlAddElementDecl: content != NULL for ANY\n",
1255 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001256 return(NULL);
1257 }
1258 break;
1259 case XML_ELEMENT_TYPE_MIXED:
1260 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001261 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1262 "xmlAddElementDecl: content == NULL for MIXED\n",
1263 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001264 return(NULL);
1265 }
1266 break;
1267 case XML_ELEMENT_TYPE_ELEMENT:
1268 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001269 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1270 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1271 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001272 return(NULL);
1273 }
1274 break;
1275 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001276 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1277 "Internal: ELEMENT decl corrupted invalid type\n",
1278 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001279 return(NULL);
1280 }
1281
1282 /*
1283 * check if name is a QName
1284 */
1285 uqname = xmlSplitQName2(name, &ns);
1286 if (uqname != NULL)
1287 name = uqname;
1288
1289 /*
1290 * Create the Element table if needed.
1291 */
1292 table = (xmlElementTablePtr) dtd->elements;
1293 if (table == NULL) {
1294 table = xmlCreateElementTable();
1295 dtd->elements = (void *) table;
1296 }
1297 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001298 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001299 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001300 if (uqname != NULL)
1301 xmlFree(uqname);
1302 if (ns != NULL)
1303 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001304 return(NULL);
1305 }
1306
Daniel Veillarda10efa82001-04-18 13:09:01 +00001307 /*
1308 * lookup old attributes inserted on an undefined element in the
1309 * internal subset.
1310 */
1311 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1312 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1313 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1314 oldAttributes = ret->attributes;
1315 ret->attributes = NULL;
1316 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1317 xmlFreeElement(ret);
1318 }
Owen Taylor3473f882001-02-23 17:55:21 +00001319 }
Owen Taylor3473f882001-02-23 17:55:21 +00001320
1321 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001322 * The element may already be present if one of its attribute
1323 * was registered first
1324 */
1325 ret = xmlHashLookup2(table, name, ns);
1326 if (ret != NULL) {
1327 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001328#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001329 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001330 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001331 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001332 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1333 "Redefinition of element %s\n",
1334 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001335#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001336 if (uqname != NULL)
1337 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001338 if (ns != NULL)
1339 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001340 return(NULL);
1341 }
1342 } else {
1343 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1344 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001345 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001346 if (uqname != NULL)
1347 xmlFree(uqname);
1348 if (ns != NULL)
1349 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001350 return(NULL);
1351 }
1352 memset(ret, 0, sizeof(xmlElement));
1353 ret->type = XML_ELEMENT_DECL;
1354
1355 /*
1356 * fill the structure.
1357 */
1358 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001359 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001360 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001361 if (uqname != NULL)
1362 xmlFree(uqname);
1363 if (ns != NULL)
1364 xmlFree(ns);
1365 xmlFree(ret);
1366 return(NULL);
1367 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001368 ret->prefix = ns;
1369
1370 /*
1371 * Validity Check:
1372 * Insertion must not fail
1373 */
1374 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001375#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001376 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001377 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001378 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001379 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1380 "Redefinition of element %s\n",
1381 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001382#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001383 xmlFreeElement(ret);
1384 if (uqname != NULL)
1385 xmlFree(uqname);
1386 return(NULL);
1387 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001388 /*
1389 * For new element, may have attributes from earlier
1390 * definition in internal subset
1391 */
1392 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001393 }
1394
1395 /*
1396 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001397 */
1398 ret->etype = type;
Owen Taylor3473f882001-02-23 17:55:21 +00001399 ret->content = xmlCopyElementContent(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001400
1401 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001402 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001403 */
1404 ret->parent = dtd;
1405 ret->doc = dtd->doc;
1406 if (dtd->last == NULL) {
1407 dtd->children = dtd->last = (xmlNodePtr) ret;
1408 } else {
1409 dtd->last->next = (xmlNodePtr) ret;
1410 ret->prev = dtd->last;
1411 dtd->last = (xmlNodePtr) ret;
1412 }
1413 if (uqname != NULL)
1414 xmlFree(uqname);
1415 return(ret);
1416}
1417
1418/**
1419 * xmlFreeElementTable:
1420 * @table: An element table
1421 *
1422 * Deallocate the memory used by an element hash table.
1423 */
1424void
1425xmlFreeElementTable(xmlElementTablePtr table) {
1426 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1427}
1428
Daniel Veillard652327a2003-09-29 18:02:38 +00001429#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001430/**
1431 * xmlCopyElement:
1432 * @elem: An element
1433 *
1434 * Build a copy of an element.
1435 *
1436 * Returns the new xmlElementPtr or NULL in case of error.
1437 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001438static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001439xmlCopyElement(xmlElementPtr elem) {
1440 xmlElementPtr cur;
1441
1442 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1443 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001444 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001445 return(NULL);
1446 }
1447 memset(cur, 0, sizeof(xmlElement));
1448 cur->type = XML_ELEMENT_DECL;
1449 cur->etype = elem->etype;
1450 if (elem->name != NULL)
1451 cur->name = xmlStrdup(elem->name);
1452 else
1453 cur->name = NULL;
1454 if (elem->prefix != NULL)
1455 cur->prefix = xmlStrdup(elem->prefix);
1456 else
1457 cur->prefix = NULL;
1458 cur->content = xmlCopyElementContent(elem->content);
1459 /* TODO : rebuild the attribute list on the copy */
1460 cur->attributes = NULL;
1461 return(cur);
1462}
1463
1464/**
1465 * xmlCopyElementTable:
1466 * @table: An element table
1467 *
1468 * Build a copy of an element table.
1469 *
1470 * Returns the new xmlElementTablePtr or NULL in case of error.
1471 */
1472xmlElementTablePtr
1473xmlCopyElementTable(xmlElementTablePtr table) {
1474 return((xmlElementTablePtr) xmlHashCopy(table,
1475 (xmlHashCopier) xmlCopyElement));
1476}
Daniel Veillard652327a2003-09-29 18:02:38 +00001477#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001478
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001479#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001480/**
1481 * xmlDumpElementDecl:
1482 * @buf: the XML buffer output
1483 * @elem: An element table
1484 *
1485 * This will dump the content of the element declaration as an XML
1486 * DTD definition
1487 */
1488void
1489xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1490 switch (elem->etype) {
1491 case XML_ELEMENT_TYPE_EMPTY:
1492 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001493 if (elem->prefix != NULL) {
1494 xmlBufferWriteCHAR(buf, elem->prefix);
1495 xmlBufferWriteChar(buf, ":");
1496 }
Owen Taylor3473f882001-02-23 17:55:21 +00001497 xmlBufferWriteCHAR(buf, elem->name);
1498 xmlBufferWriteChar(buf, " EMPTY>\n");
1499 break;
1500 case XML_ELEMENT_TYPE_ANY:
1501 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001502 if (elem->prefix != NULL) {
1503 xmlBufferWriteCHAR(buf, elem->prefix);
1504 xmlBufferWriteChar(buf, ":");
1505 }
Owen Taylor3473f882001-02-23 17:55:21 +00001506 xmlBufferWriteCHAR(buf, elem->name);
1507 xmlBufferWriteChar(buf, " ANY>\n");
1508 break;
1509 case XML_ELEMENT_TYPE_MIXED:
1510 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001511 if (elem->prefix != NULL) {
1512 xmlBufferWriteCHAR(buf, elem->prefix);
1513 xmlBufferWriteChar(buf, ":");
1514 }
Owen Taylor3473f882001-02-23 17:55:21 +00001515 xmlBufferWriteCHAR(buf, elem->name);
1516 xmlBufferWriteChar(buf, " ");
1517 xmlDumpElementContent(buf, elem->content, 1);
1518 xmlBufferWriteChar(buf, ">\n");
1519 break;
1520 case XML_ELEMENT_TYPE_ELEMENT:
1521 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001522 if (elem->prefix != NULL) {
1523 xmlBufferWriteCHAR(buf, elem->prefix);
1524 xmlBufferWriteChar(buf, ":");
1525 }
Owen Taylor3473f882001-02-23 17:55:21 +00001526 xmlBufferWriteCHAR(buf, elem->name);
1527 xmlBufferWriteChar(buf, " ");
1528 xmlDumpElementContent(buf, elem->content, 1);
1529 xmlBufferWriteChar(buf, ">\n");
1530 break;
1531 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001532 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1533 "Internal: ELEMENT struct corrupted invalid type\n",
1534 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001535 }
1536}
1537
1538/**
1539 * xmlDumpElementTable:
1540 * @buf: the XML buffer output
1541 * @table: An element table
1542 *
1543 * This will dump the content of the element table as an XML DTD definition
1544 */
1545void
1546xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1547 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDecl, buf);
1548}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001549#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001550
1551/**
1552 * xmlCreateEnumeration:
1553 * @name: the enumeration name or NULL
1554 *
1555 * create and initialize an enumeration attribute node.
1556 *
1557 * Returns the xmlEnumerationPtr just created or NULL in case
1558 * of error.
1559 */
1560xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001561xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001562 xmlEnumerationPtr ret;
1563
1564 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1565 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001566 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001567 return(NULL);
1568 }
1569 memset(ret, 0, sizeof(xmlEnumeration));
1570
1571 if (name != NULL)
1572 ret->name = xmlStrdup(name);
1573 return(ret);
1574}
1575
1576/**
1577 * xmlFreeEnumeration:
1578 * @cur: the tree to free.
1579 *
1580 * free an enumeration attribute node (recursive).
1581 */
1582void
1583xmlFreeEnumeration(xmlEnumerationPtr cur) {
1584 if (cur == NULL) return;
1585
1586 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1587
1588 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001589 xmlFree(cur);
1590}
1591
Daniel Veillard652327a2003-09-29 18:02:38 +00001592#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001593/**
1594 * xmlCopyEnumeration:
1595 * @cur: the tree to copy.
1596 *
1597 * Copy an enumeration attribute node (recursive).
1598 *
1599 * Returns the xmlEnumerationPtr just created or NULL in case
1600 * of error.
1601 */
1602xmlEnumerationPtr
1603xmlCopyEnumeration(xmlEnumerationPtr cur) {
1604 xmlEnumerationPtr ret;
1605
1606 if (cur == NULL) return(NULL);
1607 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1608
1609 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1610 else ret->next = NULL;
1611
1612 return(ret);
1613}
Daniel Veillard652327a2003-09-29 18:02:38 +00001614#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001615
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001616#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001617/**
1618 * xmlDumpEnumeration:
1619 * @buf: the XML buffer output
1620 * @enum: An enumeration
1621 *
1622 * This will dump the content of the enumeration
1623 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001624static void
Owen Taylor3473f882001-02-23 17:55:21 +00001625xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1626 if (cur == NULL) return;
1627
1628 xmlBufferWriteCHAR(buf, cur->name);
1629 if (cur->next == NULL)
1630 xmlBufferWriteChar(buf, ")");
1631 else {
1632 xmlBufferWriteChar(buf, " | ");
1633 xmlDumpEnumeration(buf, cur->next);
1634 }
1635}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001636#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001637
1638/**
1639 * xmlCreateAttributeTable:
1640 *
1641 * create and initialize an empty attribute hash table.
1642 *
1643 * Returns the xmlAttributeTablePtr just created or NULL in case
1644 * of error.
1645 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001646static xmlAttributeTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001647xmlCreateAttributeTable(void) {
1648 return(xmlHashCreate(0));
1649}
1650
Daniel Veillard4432df22003-09-28 18:58:27 +00001651#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001652/**
1653 * xmlScanAttributeDeclCallback:
1654 * @attr: the attribute decl
1655 * @list: the list to update
1656 *
1657 * Callback called by xmlScanAttributeDecl when a new attribute
1658 * has to be entered in the list.
1659 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001660static void
Owen Taylor3473f882001-02-23 17:55:21 +00001661xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001662 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001663 attr->nexth = *list;
1664 *list = attr;
1665}
1666
1667/**
1668 * xmlScanAttributeDecl:
1669 * @dtd: pointer to the DTD
1670 * @elem: the element name
1671 *
1672 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001673 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001674 *
1675 * Returns the pointer to the first attribute decl in the chain,
1676 * possibly NULL.
1677 */
1678xmlAttributePtr
1679xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1680 xmlAttributePtr ret = NULL;
1681 xmlAttributeTablePtr table;
1682
1683 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001684 return(NULL);
1685 }
1686 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001687 return(NULL);
1688 }
1689 table = (xmlAttributeTablePtr) dtd->attributes;
1690 if (table == NULL)
1691 return(NULL);
1692
1693 /* WRONG !!! */
1694 xmlHashScan3(table, NULL, NULL, elem,
1695 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1696 return(ret);
1697}
1698
1699/**
1700 * xmlScanIDAttributeDecl:
1701 * @ctxt: the validation context
1702 * @elem: the element name
1703 *
1704 * Verify that the element don't have too many ID attributes
1705 * declared.
1706 *
1707 * Returns the number of ID attributes found.
1708 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001709static int
Owen Taylor3473f882001-02-23 17:55:21 +00001710xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1711 xmlAttributePtr cur;
1712 int ret = 0;
1713
1714 if (elem == NULL) return(0);
1715 cur = elem->attributes;
1716 while (cur != NULL) {
1717 if (cur->atype == XML_ATTRIBUTE_ID) {
1718 ret ++;
1719 if (ret > 1)
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001720 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001721 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001722 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001723 }
1724 cur = cur->nexth;
1725 }
1726 return(ret);
1727}
Daniel Veillard4432df22003-09-28 18:58:27 +00001728#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001729
1730/**
1731 * xmlFreeAttribute:
1732 * @elem: An attribute
1733 *
1734 * Deallocate the memory used by an attribute definition
1735 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001736static void
Owen Taylor3473f882001-02-23 17:55:21 +00001737xmlFreeAttribute(xmlAttributePtr attr) {
1738 if (attr == NULL) return;
1739 xmlUnlinkNode((xmlNodePtr) attr);
1740 if (attr->tree != NULL)
1741 xmlFreeEnumeration(attr->tree);
1742 if (attr->elem != NULL)
1743 xmlFree((xmlChar *) attr->elem);
1744 if (attr->name != NULL)
1745 xmlFree((xmlChar *) attr->name);
1746 if (attr->defaultValue != NULL)
1747 xmlFree((xmlChar *) attr->defaultValue);
1748 if (attr->prefix != NULL)
1749 xmlFree((xmlChar *) attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001750 xmlFree(attr);
1751}
1752
1753
1754/**
1755 * xmlAddAttributeDecl:
1756 * @ctxt: the validation context
1757 * @dtd: pointer to the DTD
1758 * @elem: the element name
1759 * @name: the attribute name
1760 * @ns: the attribute namespace prefix
1761 * @type: the attribute type
1762 * @def: the attribute default type
1763 * @defaultValue: the attribute default value
1764 * @tree: if it's an enumeration, the associated list
1765 *
1766 * Register a new attribute declaration
1767 * Note that @tree becomes the ownership of the DTD
1768 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001769 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001770 */
1771xmlAttributePtr
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001772xmlAddAttributeDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1773 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001774 const xmlChar *name, const xmlChar *ns,
1775 xmlAttributeType type, xmlAttributeDefault def,
1776 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1777 xmlAttributePtr ret;
1778 xmlAttributeTablePtr table;
1779 xmlElementPtr elemDef;
1780
1781 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001782 xmlFreeEnumeration(tree);
1783 return(NULL);
1784 }
1785 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001786 xmlFreeEnumeration(tree);
1787 return(NULL);
1788 }
1789 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001790 xmlFreeEnumeration(tree);
1791 return(NULL);
1792 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001793
Daniel Veillard4432df22003-09-28 18:58:27 +00001794#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001795 /*
1796 * Check the type and possibly the default value.
1797 */
1798 switch (type) {
1799 case XML_ATTRIBUTE_CDATA:
1800 break;
1801 case XML_ATTRIBUTE_ID:
1802 break;
1803 case XML_ATTRIBUTE_IDREF:
1804 break;
1805 case XML_ATTRIBUTE_IDREFS:
1806 break;
1807 case XML_ATTRIBUTE_ENTITY:
1808 break;
1809 case XML_ATTRIBUTE_ENTITIES:
1810 break;
1811 case XML_ATTRIBUTE_NMTOKEN:
1812 break;
1813 case XML_ATTRIBUTE_NMTOKENS:
1814 break;
1815 case XML_ATTRIBUTE_ENUMERATION:
1816 break;
1817 case XML_ATTRIBUTE_NOTATION:
1818 break;
1819 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001820 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1821 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1822 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001823 xmlFreeEnumeration(tree);
1824 return(NULL);
1825 }
1826 if ((defaultValue != NULL) &&
1827 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001828 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1829 "Attribute %s of %s: invalid default value\n",
1830 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00001831 defaultValue = NULL;
Daniel Veillardd01fd3e2002-02-18 22:27:47 +00001832 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001833 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001834#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001835
1836 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001837 * Check first that an attribute defined in the external subset wasn't
1838 * already defined in the internal subset
1839 */
1840 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1841 (dtd->doc->intSubset != NULL) &&
1842 (dtd->doc->intSubset->attributes != NULL)) {
1843 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1844 if (ret != NULL)
1845 return(NULL);
1846 }
1847
1848 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001849 * Create the Attribute table if needed.
1850 */
1851 table = (xmlAttributeTablePtr) dtd->attributes;
1852 if (table == NULL) {
1853 table = xmlCreateAttributeTable();
1854 dtd->attributes = (void *) table;
1855 }
1856 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001857 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001858 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001859 return(NULL);
1860 }
1861
1862
1863 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1864 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001865 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001866 return(NULL);
1867 }
1868 memset(ret, 0, sizeof(xmlAttribute));
1869 ret->type = XML_ATTRIBUTE_DECL;
1870
1871 /*
1872 * fill the structure.
1873 */
1874 ret->atype = type;
1875 ret->name = xmlStrdup(name);
1876 ret->prefix = xmlStrdup(ns);
1877 ret->elem = xmlStrdup(elem);
1878 ret->def = def;
1879 ret->tree = tree;
1880 if (defaultValue != NULL)
1881 ret->defaultValue = xmlStrdup(defaultValue);
1882
1883 /*
1884 * Validity Check:
1885 * Search the DTD for previous declarations of the ATTLIST
1886 */
1887 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001888#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001889 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001890 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00001891 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001892 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00001893 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001894 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001895#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001896 xmlFreeAttribute(ret);
1897 return(NULL);
1898 }
1899
1900 /*
1901 * Validity Check:
1902 * Multiple ID per element
1903 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001904 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001905 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00001906
Daniel Veillard4432df22003-09-28 18:58:27 +00001907#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001908 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00001909 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001910 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00001911 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001912 elem, name, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00001913 ctxt->valid = 0;
1914 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001915#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00001916
Daniel Veillard48da9102001-08-07 01:10:10 +00001917 /*
1918 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001919 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00001920 */
1921 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1922 ((ret->prefix != NULL &&
1923 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1924 ret->nexth = elemDef->attributes;
1925 elemDef->attributes = ret;
1926 } else {
1927 xmlAttributePtr tmp = elemDef->attributes;
1928
1929 while ((tmp != NULL) &&
1930 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1931 ((ret->prefix != NULL &&
1932 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1933 if (tmp->nexth == NULL)
1934 break;
1935 tmp = tmp->nexth;
1936 }
1937 if (tmp != NULL) {
1938 ret->nexth = tmp->nexth;
1939 tmp->nexth = ret;
1940 } else {
1941 ret->nexth = elemDef->attributes;
1942 elemDef->attributes = ret;
1943 }
1944 }
Owen Taylor3473f882001-02-23 17:55:21 +00001945 }
1946
1947 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001948 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001949 */
1950 ret->parent = dtd;
1951 ret->doc = dtd->doc;
1952 if (dtd->last == NULL) {
1953 dtd->children = dtd->last = (xmlNodePtr) ret;
1954 } else {
1955 dtd->last->next = (xmlNodePtr) ret;
1956 ret->prev = dtd->last;
1957 dtd->last = (xmlNodePtr) ret;
1958 }
1959 return(ret);
1960}
1961
1962/**
1963 * xmlFreeAttributeTable:
1964 * @table: An attribute table
1965 *
1966 * Deallocate the memory used by an entities hash table.
1967 */
1968void
1969xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1970 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
1971}
1972
Daniel Veillard652327a2003-09-29 18:02:38 +00001973#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001974/**
1975 * xmlCopyAttribute:
1976 * @attr: An attribute
1977 *
1978 * Build a copy of an attribute.
1979 *
1980 * Returns the new xmlAttributePtr or NULL in case of error.
1981 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001982static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001983xmlCopyAttribute(xmlAttributePtr attr) {
1984 xmlAttributePtr cur;
1985
1986 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1987 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001988 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001989 return(NULL);
1990 }
1991 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00001992 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00001993 cur->atype = attr->atype;
1994 cur->def = attr->def;
1995 cur->tree = xmlCopyEnumeration(attr->tree);
1996 if (attr->elem != NULL)
1997 cur->elem = xmlStrdup(attr->elem);
1998 if (attr->name != NULL)
1999 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002000 if (attr->prefix != NULL)
2001 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002002 if (attr->defaultValue != NULL)
2003 cur->defaultValue = xmlStrdup(attr->defaultValue);
2004 return(cur);
2005}
2006
2007/**
2008 * xmlCopyAttributeTable:
2009 * @table: An attribute table
2010 *
2011 * Build a copy of an attribute table.
2012 *
2013 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2014 */
2015xmlAttributeTablePtr
2016xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2017 return((xmlAttributeTablePtr) xmlHashCopy(table,
2018 (xmlHashCopier) xmlCopyAttribute));
2019}
Daniel Veillard652327a2003-09-29 18:02:38 +00002020#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002021
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002022#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002023/**
2024 * xmlDumpAttributeDecl:
2025 * @buf: the XML buffer output
2026 * @attr: An attribute declaration
2027 *
2028 * This will dump the content of the attribute declaration as an XML
2029 * DTD definition
2030 */
2031void
2032xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2033 xmlBufferWriteChar(buf, "<!ATTLIST ");
2034 xmlBufferWriteCHAR(buf, attr->elem);
2035 xmlBufferWriteChar(buf, " ");
2036 if (attr->prefix != NULL) {
2037 xmlBufferWriteCHAR(buf, attr->prefix);
2038 xmlBufferWriteChar(buf, ":");
2039 }
2040 xmlBufferWriteCHAR(buf, attr->name);
2041 switch (attr->atype) {
2042 case XML_ATTRIBUTE_CDATA:
2043 xmlBufferWriteChar(buf, " CDATA");
2044 break;
2045 case XML_ATTRIBUTE_ID:
2046 xmlBufferWriteChar(buf, " ID");
2047 break;
2048 case XML_ATTRIBUTE_IDREF:
2049 xmlBufferWriteChar(buf, " IDREF");
2050 break;
2051 case XML_ATTRIBUTE_IDREFS:
2052 xmlBufferWriteChar(buf, " IDREFS");
2053 break;
2054 case XML_ATTRIBUTE_ENTITY:
2055 xmlBufferWriteChar(buf, " ENTITY");
2056 break;
2057 case XML_ATTRIBUTE_ENTITIES:
2058 xmlBufferWriteChar(buf, " ENTITIES");
2059 break;
2060 case XML_ATTRIBUTE_NMTOKEN:
2061 xmlBufferWriteChar(buf, " NMTOKEN");
2062 break;
2063 case XML_ATTRIBUTE_NMTOKENS:
2064 xmlBufferWriteChar(buf, " NMTOKENS");
2065 break;
2066 case XML_ATTRIBUTE_ENUMERATION:
2067 xmlBufferWriteChar(buf, " (");
2068 xmlDumpEnumeration(buf, attr->tree);
2069 break;
2070 case XML_ATTRIBUTE_NOTATION:
2071 xmlBufferWriteChar(buf, " NOTATION (");
2072 xmlDumpEnumeration(buf, attr->tree);
2073 break;
2074 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002075 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2076 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2077 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002078 }
2079 switch (attr->def) {
2080 case XML_ATTRIBUTE_NONE:
2081 break;
2082 case XML_ATTRIBUTE_REQUIRED:
2083 xmlBufferWriteChar(buf, " #REQUIRED");
2084 break;
2085 case XML_ATTRIBUTE_IMPLIED:
2086 xmlBufferWriteChar(buf, " #IMPLIED");
2087 break;
2088 case XML_ATTRIBUTE_FIXED:
2089 xmlBufferWriteChar(buf, " #FIXED");
2090 break;
2091 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002092 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2093 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2094 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002095 }
2096 if (attr->defaultValue != NULL) {
2097 xmlBufferWriteChar(buf, " ");
2098 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2099 }
2100 xmlBufferWriteChar(buf, ">\n");
2101}
2102
2103/**
2104 * xmlDumpAttributeTable:
2105 * @buf: the XML buffer output
2106 * @table: An attribute table
2107 *
2108 * This will dump the content of the attribute table as an XML DTD definition
2109 */
2110void
2111xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
2112 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDecl, buf);
2113}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002114#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002115
2116/************************************************************************
2117 * *
2118 * NOTATIONs *
2119 * *
2120 ************************************************************************/
2121/**
2122 * xmlCreateNotationTable:
2123 *
2124 * create and initialize an empty notation hash table.
2125 *
2126 * Returns the xmlNotationTablePtr just created or NULL in case
2127 * of error.
2128 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002129static xmlNotationTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002130xmlCreateNotationTable(void) {
2131 return(xmlHashCreate(0));
2132}
2133
2134/**
2135 * xmlFreeNotation:
2136 * @not: A notation
2137 *
2138 * Deallocate the memory used by an notation definition
2139 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002140static void
Owen Taylor3473f882001-02-23 17:55:21 +00002141xmlFreeNotation(xmlNotationPtr nota) {
2142 if (nota == NULL) return;
2143 if (nota->name != NULL)
2144 xmlFree((xmlChar *) nota->name);
2145 if (nota->PublicID != NULL)
2146 xmlFree((xmlChar *) nota->PublicID);
2147 if (nota->SystemID != NULL)
2148 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002149 xmlFree(nota);
2150}
2151
2152
2153/**
2154 * xmlAddNotationDecl:
2155 * @dtd: pointer to the DTD
2156 * @ctxt: the validation context
2157 * @name: the entity name
2158 * @PublicID: the public identifier or NULL
2159 * @SystemID: the system identifier or NULL
2160 *
2161 * Register a new notation declaration
2162 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002163 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002164 */
2165xmlNotationPtr
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00002166xmlAddNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002167 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002168 const xmlChar *PublicID, const xmlChar *SystemID) {
2169 xmlNotationPtr ret;
2170 xmlNotationTablePtr table;
2171
2172 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002173 return(NULL);
2174 }
2175 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002176 return(NULL);
2177 }
2178 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002179 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002180 }
2181
2182 /*
2183 * Create the Notation table if needed.
2184 */
2185 table = (xmlNotationTablePtr) dtd->notations;
2186 if (table == NULL)
2187 dtd->notations = table = xmlCreateNotationTable();
2188 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002189 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002190 "xmlAddNotationDecl: Table creation failed!\n");
2191 return(NULL);
2192 }
2193
2194 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2195 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002196 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002197 return(NULL);
2198 }
2199 memset(ret, 0, sizeof(xmlNotation));
2200
2201 /*
2202 * fill the structure.
2203 */
2204 ret->name = xmlStrdup(name);
2205 if (SystemID != NULL)
2206 ret->SystemID = xmlStrdup(SystemID);
2207 if (PublicID != NULL)
2208 ret->PublicID = xmlStrdup(PublicID);
2209
2210 /*
2211 * Validity Check:
2212 * Check the DTD for previous declarations of the ATTLIST
2213 */
2214 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002215#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002216 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2217 "xmlAddNotationDecl: %s already defined\n",
2218 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002219#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002220 xmlFreeNotation(ret);
2221 return(NULL);
2222 }
2223 return(ret);
2224}
2225
2226/**
2227 * xmlFreeNotationTable:
2228 * @table: An notation table
2229 *
2230 * Deallocate the memory used by an entities hash table.
2231 */
2232void
2233xmlFreeNotationTable(xmlNotationTablePtr table) {
2234 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2235}
2236
Daniel Veillard652327a2003-09-29 18:02:38 +00002237#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002238/**
2239 * xmlCopyNotation:
2240 * @nota: A notation
2241 *
2242 * Build a copy of a notation.
2243 *
2244 * Returns the new xmlNotationPtr or NULL in case of error.
2245 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002246static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002247xmlCopyNotation(xmlNotationPtr nota) {
2248 xmlNotationPtr cur;
2249
2250 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2251 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002252 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002253 return(NULL);
2254 }
2255 if (nota->name != NULL)
2256 cur->name = xmlStrdup(nota->name);
2257 else
2258 cur->name = NULL;
2259 if (nota->PublicID != NULL)
2260 cur->PublicID = xmlStrdup(nota->PublicID);
2261 else
2262 cur->PublicID = NULL;
2263 if (nota->SystemID != NULL)
2264 cur->SystemID = xmlStrdup(nota->SystemID);
2265 else
2266 cur->SystemID = NULL;
2267 return(cur);
2268}
2269
2270/**
2271 * xmlCopyNotationTable:
2272 * @table: A notation table
2273 *
2274 * Build a copy of a notation table.
2275 *
2276 * Returns the new xmlNotationTablePtr or NULL in case of error.
2277 */
2278xmlNotationTablePtr
2279xmlCopyNotationTable(xmlNotationTablePtr table) {
2280 return((xmlNotationTablePtr) xmlHashCopy(table,
2281 (xmlHashCopier) xmlCopyNotation));
2282}
Daniel Veillard652327a2003-09-29 18:02:38 +00002283#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002284
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002285#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002286/**
2287 * xmlDumpNotationDecl:
2288 * @buf: the XML buffer output
2289 * @nota: A notation declaration
2290 *
2291 * This will dump the content the notation declaration as an XML DTD definition
2292 */
2293void
2294xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2295 xmlBufferWriteChar(buf, "<!NOTATION ");
2296 xmlBufferWriteCHAR(buf, nota->name);
2297 if (nota->PublicID != NULL) {
2298 xmlBufferWriteChar(buf, " PUBLIC ");
2299 xmlBufferWriteQuotedString(buf, nota->PublicID);
2300 if (nota->SystemID != NULL) {
2301 xmlBufferWriteChar(buf, " ");
2302 xmlBufferWriteCHAR(buf, nota->SystemID);
2303 }
2304 } else {
2305 xmlBufferWriteChar(buf, " SYSTEM ");
2306 xmlBufferWriteCHAR(buf, nota->SystemID);
2307 }
2308 xmlBufferWriteChar(buf, " >\n");
2309}
2310
2311/**
2312 * xmlDumpNotationTable:
2313 * @buf: the XML buffer output
2314 * @table: A notation table
2315 *
2316 * This will dump the content of the notation table as an XML DTD definition
2317 */
2318void
2319xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2320 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDecl, buf);
2321}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002322#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002323
2324/************************************************************************
2325 * *
2326 * IDs *
2327 * *
2328 ************************************************************************/
2329/**
2330 * xmlCreateIDTable:
2331 *
2332 * create and initialize an empty id hash table.
2333 *
2334 * Returns the xmlIDTablePtr just created or NULL in case
2335 * of error.
2336 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002337static xmlIDTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002338xmlCreateIDTable(void) {
2339 return(xmlHashCreate(0));
2340}
2341
2342/**
2343 * xmlFreeID:
2344 * @not: A id
2345 *
2346 * Deallocate the memory used by an id definition
2347 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002348static void
Owen Taylor3473f882001-02-23 17:55:21 +00002349xmlFreeID(xmlIDPtr id) {
2350 if (id == NULL) return;
2351 if (id->value != NULL)
2352 xmlFree((xmlChar *) id->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002353 if (id->name != NULL)
2354 xmlFree((xmlChar *) id->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002355 xmlFree(id);
2356}
2357
2358/**
2359 * xmlAddID:
2360 * @ctxt: the validation context
2361 * @doc: pointer to the document
2362 * @value: the value name
2363 * @attr: the attribute holding the ID
2364 *
2365 * Register a new id declaration
2366 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002367 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002368 */
2369xmlIDPtr
2370xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2371 xmlAttrPtr attr) {
2372 xmlIDPtr ret;
2373 xmlIDTablePtr table;
2374
2375 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002376 return(NULL);
2377 }
2378 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002379 return(NULL);
2380 }
2381 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002382 return(NULL);
2383 }
2384
2385 /*
2386 * Create the ID table if needed.
2387 */
2388 table = (xmlIDTablePtr) doc->ids;
2389 if (table == NULL)
2390 doc->ids = table = xmlCreateIDTable();
2391 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002392 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002393 "xmlAddID: Table creation failed!\n");
2394 return(NULL);
2395 }
2396
2397 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2398 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002399 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002400 return(NULL);
2401 }
2402
2403 /*
2404 * fill the structure.
2405 */
2406 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002407 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2408 /*
2409 * Operating in streaming mode, attr is gonna disapear
2410 */
2411 ret->name = xmlStrdup(attr->name);
2412 ret->attr = NULL;
2413 } else {
2414 ret->attr = attr;
2415 ret->name = NULL;
2416 }
2417 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002418
2419 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002420#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002421 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002422 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002423 */
Daniel Veillard76575762002-09-05 14:21:15 +00002424 if (ctxt != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002425 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2426 "ID %s already defined\n",
2427 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002428 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002429#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002430 xmlFreeID(ret);
2431 return(NULL);
2432 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002433 if (attr != NULL)
2434 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002435 return(ret);
2436}
2437
2438/**
2439 * xmlFreeIDTable:
2440 * @table: An id table
2441 *
2442 * Deallocate the memory used by an ID hash table.
2443 */
2444void
2445xmlFreeIDTable(xmlIDTablePtr table) {
2446 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2447}
2448
2449/**
2450 * xmlIsID:
2451 * @doc: the document
2452 * @elem: the element carrying the attribute
2453 * @attr: the attribute
2454 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002455 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002456 * then this is done if DTD loading has been requested. In the case
2457 * of HTML documents parsed with the HTML parser, then ID detection is
2458 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002459 *
2460 * Returns 0 or 1 depending on the lookup result
2461 */
2462int
2463xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2464 if (doc == NULL) return(0);
2465 if (attr == NULL) return(0);
2466 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2467 return(0);
2468 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2469 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2470 (xmlStrEqual(BAD_CAST "name", attr->name)))
2471 return(1);
2472 return(0);
2473 } else {
2474 xmlAttributePtr attrDecl;
2475
2476 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002477 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002478 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002479 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002480
2481 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002482 if (fullname == NULL)
2483 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002484 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2485 attr->name);
2486 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2487 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2488 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002489 if ((fullname != fn) && (fullname != elem->name))
2490 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002491 } else {
2492 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2493 attr->name);
2494 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2495 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2496 attr->name);
2497 }
Owen Taylor3473f882001-02-23 17:55:21 +00002498
2499 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2500 return(1);
2501 }
2502 return(0);
2503}
2504
2505/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002506 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002507 * @doc: the document
2508 * @attr: the attribute
2509 *
2510 * Remove the given attribute from the ID table maintained internally.
2511 *
2512 * Returns -1 if the lookup failed and 0 otherwise
2513 */
2514int
2515xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2516 xmlAttrPtr cur;
2517 xmlIDTablePtr table;
2518 xmlChar *ID;
2519
2520 if (doc == NULL) return(-1);
2521 if (attr == NULL) return(-1);
2522 table = (xmlIDTablePtr) doc->ids;
2523 if (table == NULL)
2524 return(-1);
2525
2526 if (attr == NULL)
2527 return(-1);
2528 ID = xmlNodeListGetString(doc, attr->children, 1);
2529 if (ID == NULL)
2530 return(-1);
2531 cur = xmlHashLookup(table, ID);
2532 if (cur != attr) {
2533 xmlFree(ID);
2534 return(-1);
2535 }
2536 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
2537 xmlFree(ID);
2538 return(0);
2539}
2540
2541/**
2542 * xmlGetID:
2543 * @doc: pointer to the document
2544 * @ID: the ID value
2545 *
2546 * Search the attribute declaring the given ID
2547 *
2548 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2549 */
2550xmlAttrPtr
2551xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2552 xmlIDTablePtr table;
2553 xmlIDPtr id;
2554
2555 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002556 return(NULL);
2557 }
2558
2559 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002560 return(NULL);
2561 }
2562
2563 table = (xmlIDTablePtr) doc->ids;
2564 if (table == NULL)
2565 return(NULL);
2566
2567 id = xmlHashLookup(table, ID);
2568 if (id == NULL)
2569 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002570 if (id->attr == NULL) {
2571 /*
2572 * We are operating on a stream, return a well known reference
2573 * since the attribute node doesn't exist anymore
2574 */
2575 return((xmlAttrPtr) doc);
2576 }
Owen Taylor3473f882001-02-23 17:55:21 +00002577 return(id->attr);
2578}
2579
2580/************************************************************************
2581 * *
2582 * Refs *
2583 * *
2584 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002585typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002586{
2587 xmlListPtr l;
2588 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002589} xmlRemoveMemo;
2590
2591typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2592
2593typedef struct xmlValidateMemo_t
2594{
2595 xmlValidCtxtPtr ctxt;
2596 const xmlChar *name;
2597} xmlValidateMemo;
2598
2599typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002600
2601/**
2602 * xmlCreateRefTable:
2603 *
2604 * create and initialize an empty ref hash table.
2605 *
2606 * Returns the xmlRefTablePtr just created or NULL in case
2607 * of error.
2608 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002609static xmlRefTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002610xmlCreateRefTable(void) {
2611 return(xmlHashCreate(0));
2612}
2613
2614/**
2615 * xmlFreeRef:
2616 * @lk: A list link
2617 *
2618 * Deallocate the memory used by a ref definition
2619 */
2620static void
2621xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002622 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2623 if (ref == NULL) return;
2624 if (ref->value != NULL)
2625 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002626 if (ref->name != NULL)
2627 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002628 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002629}
2630
2631/**
2632 * xmlFreeRefList:
2633 * @list_ref: A list of references.
2634 *
2635 * Deallocate the memory used by a list of references
2636 */
2637static void
2638xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002639 if (list_ref == NULL) return;
2640 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002641}
2642
2643/**
2644 * xmlWalkRemoveRef:
2645 * @data: Contents of current link
2646 * @user: Value supplied by the user
2647 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002648 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002649 */
2650static int
2651xmlWalkRemoveRef(const void *data, const void *user)
2652{
Daniel Veillard37721922001-05-04 15:21:12 +00002653 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2654 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2655 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002656
Daniel Veillard37721922001-05-04 15:21:12 +00002657 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2658 xmlListRemoveFirst(ref_list, (void *)data);
2659 return 0;
2660 }
2661 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002662}
2663
2664/**
2665 * xmlAddRef:
2666 * @ctxt: the validation context
2667 * @doc: pointer to the document
2668 * @value: the value name
2669 * @attr: the attribute holding the Ref
2670 *
2671 * Register a new ref declaration
2672 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002673 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002674 */
2675xmlRefPtr
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00002676xmlAddRef(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002677 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002678 xmlRefPtr ret;
2679 xmlRefTablePtr table;
2680 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002681
Daniel Veillard37721922001-05-04 15:21:12 +00002682 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002683 return(NULL);
2684 }
2685 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002686 return(NULL);
2687 }
2688 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002689 return(NULL);
2690 }
Owen Taylor3473f882001-02-23 17:55:21 +00002691
Daniel Veillard37721922001-05-04 15:21:12 +00002692 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002693 * Create the Ref table if needed.
2694 */
Daniel Veillard37721922001-05-04 15:21:12 +00002695 table = (xmlRefTablePtr) doc->refs;
2696 if (table == NULL)
2697 doc->refs = table = xmlCreateRefTable();
2698 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002699 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002700 "xmlAddRef: Table creation failed!\n");
2701 return(NULL);
2702 }
Owen Taylor3473f882001-02-23 17:55:21 +00002703
Daniel Veillard37721922001-05-04 15:21:12 +00002704 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2705 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002706 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002707 return(NULL);
2708 }
Owen Taylor3473f882001-02-23 17:55:21 +00002709
Daniel Veillard37721922001-05-04 15:21:12 +00002710 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002711 * fill the structure.
2712 */
Daniel Veillard37721922001-05-04 15:21:12 +00002713 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002714 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2715 /*
2716 * Operating in streaming mode, attr is gonna disapear
2717 */
2718 ret->name = xmlStrdup(attr->name);
2719 ret->attr = NULL;
2720 } else {
2721 ret->name = NULL;
2722 ret->attr = attr;
2723 }
2724 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002725
Daniel Veillard37721922001-05-04 15:21:12 +00002726 /* To add a reference :-
2727 * References are maintained as a list of references,
2728 * Lookup the entry, if no entry create new nodelist
2729 * Add the owning node to the NodeList
2730 * Return the ref
2731 */
Owen Taylor3473f882001-02-23 17:55:21 +00002732
Daniel Veillard37721922001-05-04 15:21:12 +00002733 if (NULL == (ref_list = xmlHashLookup(table, value))) {
2734 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, NULL))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002735 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2736 "xmlAddRef: Reference list creation failed!\n",
2737 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002738 return(NULL);
2739 }
2740 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2741 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002742 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2743 "xmlAddRef: Reference list insertion failed!\n",
2744 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002745 return(NULL);
2746 }
2747 }
2748 xmlListInsert(ref_list, ret);
2749 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002750}
2751
2752/**
2753 * xmlFreeRefTable:
2754 * @table: An ref table
2755 *
2756 * Deallocate the memory used by an Ref hash table.
2757 */
2758void
2759xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002760 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002761}
2762
2763/**
2764 * xmlIsRef:
2765 * @doc: the document
2766 * @elem: the element carrying the attribute
2767 * @attr: the attribute
2768 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002769 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00002770 * then this is simple, otherwise we use an heuristic: name Ref (upper
2771 * or lowercase).
2772 *
2773 * Returns 0 or 1 depending on the lookup result
2774 */
2775int
2776xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002777 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2778 return(0);
2779 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2780 /* TODO @@@ */
2781 return(0);
2782 } else {
2783 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00002784
Daniel Veillard37721922001-05-04 15:21:12 +00002785 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2786 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2787 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2788 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002789
Daniel Veillard37721922001-05-04 15:21:12 +00002790 if ((attrDecl != NULL) &&
2791 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2792 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2793 return(1);
2794 }
2795 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002796}
2797
2798/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002799 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00002800 * @doc: the document
2801 * @attr: the attribute
2802 *
2803 * Remove the given attribute from the Ref table maintained internally.
2804 *
2805 * Returns -1 if the lookup failed and 0 otherwise
2806 */
2807int
2808xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002809 xmlListPtr ref_list;
2810 xmlRefTablePtr table;
2811 xmlChar *ID;
2812 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00002813
Daniel Veillard37721922001-05-04 15:21:12 +00002814 if (doc == NULL) return(-1);
2815 if (attr == NULL) return(-1);
2816 table = (xmlRefTablePtr) doc->refs;
2817 if (table == NULL)
2818 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002819
Daniel Veillard37721922001-05-04 15:21:12 +00002820 if (attr == NULL)
2821 return(-1);
2822 ID = xmlNodeListGetString(doc, attr->children, 1);
2823 if (ID == NULL)
2824 return(-1);
2825 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00002826
Daniel Veillard37721922001-05-04 15:21:12 +00002827 if(ref_list == NULL) {
2828 xmlFree(ID);
2829 return (-1);
2830 }
2831 /* At this point, ref_list refers to a list of references which
2832 * have the same key as the supplied attr. Our list of references
2833 * is ordered by reference address and we don't have that information
2834 * here to use when removing. We'll have to walk the list and
2835 * check for a matching attribute, when we find one stop the walk
2836 * and remove the entry.
2837 * The list is ordered by reference, so that means we don't have the
2838 * key. Passing the list and the reference to the walker means we
2839 * will have enough data to be able to remove the entry.
2840 */
2841 target.l = ref_list;
2842 target.ap = attr;
2843
2844 /* Remove the supplied attr from our list */
2845 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00002846
Daniel Veillard37721922001-05-04 15:21:12 +00002847 /*If the list is empty then remove the list entry in the hash */
2848 if (xmlListEmpty(ref_list))
2849 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2850 xmlFreeRefList);
2851 xmlFree(ID);
2852 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002853}
2854
2855/**
2856 * xmlGetRefs:
2857 * @doc: pointer to the document
2858 * @ID: the ID value
2859 *
2860 * Find the set of references for the supplied ID.
2861 *
2862 * Returns NULL if not found, otherwise node set for the ID.
2863 */
2864xmlListPtr
2865xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00002866 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00002867
Daniel Veillard37721922001-05-04 15:21:12 +00002868 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002869 return(NULL);
2870 }
Owen Taylor3473f882001-02-23 17:55:21 +00002871
Daniel Veillard37721922001-05-04 15:21:12 +00002872 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002873 return(NULL);
2874 }
Owen Taylor3473f882001-02-23 17:55:21 +00002875
Daniel Veillard37721922001-05-04 15:21:12 +00002876 table = (xmlRefTablePtr) doc->refs;
2877 if (table == NULL)
2878 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002879
Daniel Veillard37721922001-05-04 15:21:12 +00002880 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00002881}
2882
2883/************************************************************************
2884 * *
2885 * Routines for validity checking *
2886 * *
2887 ************************************************************************/
2888
2889/**
2890 * xmlGetDtdElementDesc:
2891 * @dtd: a pointer to the DtD to search
2892 * @name: the element name
2893 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002894 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002895 *
2896 * returns the xmlElementPtr if found or NULL
2897 */
2898
2899xmlElementPtr
2900xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2901 xmlElementTablePtr table;
2902 xmlElementPtr cur;
2903 xmlChar *uqname = NULL, *prefix = NULL;
2904
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002905 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002906 if (dtd->elements == NULL)
2907 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002908 table = (xmlElementTablePtr) dtd->elements;
2909
2910 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002911 if (uqname != NULL)
2912 name = uqname;
2913 cur = xmlHashLookup2(table, name, prefix);
2914 if (prefix != NULL) xmlFree(prefix);
2915 if (uqname != NULL) xmlFree(uqname);
2916 return(cur);
2917}
2918/**
2919 * xmlGetDtdElementDesc2:
2920 * @dtd: a pointer to the DtD to search
2921 * @name: the element name
2922 * @create: create an empty description if not found
2923 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002924 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00002925 *
2926 * returns the xmlElementPtr if found or NULL
2927 */
2928
Daniel Veillard86fd5a72001-12-13 14:55:21 +00002929static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00002930xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
2931 xmlElementTablePtr table;
2932 xmlElementPtr cur;
2933 xmlChar *uqname = NULL, *prefix = NULL;
2934
2935 if (dtd == NULL) return(NULL);
2936 if (dtd->elements == NULL) {
2937 if (!create)
2938 return(NULL);
2939 /*
2940 * Create the Element table if needed.
2941 */
2942 table = (xmlElementTablePtr) dtd->elements;
2943 if (table == NULL) {
2944 table = xmlCreateElementTable();
2945 dtd->elements = (void *) table;
2946 }
2947 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002948 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00002949 return(NULL);
2950 }
2951 }
2952 table = (xmlElementTablePtr) dtd->elements;
2953
2954 uqname = xmlSplitQName2(name, &prefix);
2955 if (uqname != NULL)
2956 name = uqname;
2957 cur = xmlHashLookup2(table, name, prefix);
2958 if ((cur == NULL) && (create)) {
2959 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
2960 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002961 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00002962 return(NULL);
2963 }
2964 memset(cur, 0, sizeof(xmlElement));
2965 cur->type = XML_ELEMENT_DECL;
2966
2967 /*
2968 * fill the structure.
2969 */
2970 cur->name = xmlStrdup(name);
2971 cur->prefix = xmlStrdup(prefix);
2972 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
2973
2974 xmlHashAddEntry2(table, name, prefix, cur);
2975 }
2976 if (prefix != NULL) xmlFree(prefix);
2977 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00002978 return(cur);
2979}
2980
2981/**
2982 * xmlGetDtdQElementDesc:
2983 * @dtd: a pointer to the DtD to search
2984 * @name: the element name
2985 * @prefix: the element namespace prefix
2986 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002987 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002988 *
2989 * returns the xmlElementPtr if found or NULL
2990 */
2991
Daniel Veillard48da9102001-08-07 01:10:10 +00002992xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002993xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
2994 const xmlChar *prefix) {
2995 xmlElementTablePtr table;
2996
2997 if (dtd == NULL) return(NULL);
2998 if (dtd->elements == NULL) return(NULL);
2999 table = (xmlElementTablePtr) dtd->elements;
3000
3001 return(xmlHashLookup2(table, name, prefix));
3002}
3003
3004/**
3005 * xmlGetDtdAttrDesc:
3006 * @dtd: a pointer to the DtD to search
3007 * @elem: the element name
3008 * @name: the attribute name
3009 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003010 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003011 * this element.
3012 *
3013 * returns the xmlAttributePtr if found or NULL
3014 */
3015
3016xmlAttributePtr
3017xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3018 xmlAttributeTablePtr table;
3019 xmlAttributePtr cur;
3020 xmlChar *uqname = NULL, *prefix = NULL;
3021
3022 if (dtd == NULL) return(NULL);
3023 if (dtd->attributes == NULL) return(NULL);
3024
3025 table = (xmlAttributeTablePtr) dtd->attributes;
3026 if (table == NULL)
3027 return(NULL);
3028
3029 uqname = xmlSplitQName2(name, &prefix);
3030
3031 if (uqname != NULL) {
3032 cur = xmlHashLookup3(table, uqname, prefix, elem);
3033 if (prefix != NULL) xmlFree(prefix);
3034 if (uqname != NULL) xmlFree(uqname);
3035 } else
3036 cur = xmlHashLookup3(table, name, NULL, elem);
3037 return(cur);
3038}
3039
3040/**
3041 * xmlGetDtdQAttrDesc:
3042 * @dtd: a pointer to the DtD to search
3043 * @elem: the element name
3044 * @name: the attribute name
3045 * @prefix: the attribute namespace prefix
3046 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003047 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003048 * this element.
3049 *
3050 * returns the xmlAttributePtr if found or NULL
3051 */
3052
Daniel Veillard48da9102001-08-07 01:10:10 +00003053xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003054xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3055 const xmlChar *prefix) {
3056 xmlAttributeTablePtr table;
3057
3058 if (dtd == NULL) return(NULL);
3059 if (dtd->attributes == NULL) return(NULL);
3060 table = (xmlAttributeTablePtr) dtd->attributes;
3061
3062 return(xmlHashLookup3(table, name, prefix, elem));
3063}
3064
3065/**
3066 * xmlGetDtdNotationDesc:
3067 * @dtd: a pointer to the DtD to search
3068 * @name: the notation name
3069 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003070 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003071 *
3072 * returns the xmlNotationPtr if found or NULL
3073 */
3074
3075xmlNotationPtr
3076xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3077 xmlNotationTablePtr table;
3078
3079 if (dtd == NULL) return(NULL);
3080 if (dtd->notations == NULL) return(NULL);
3081 table = (xmlNotationTablePtr) dtd->notations;
3082
3083 return(xmlHashLookup(table, name));
3084}
3085
Daniel Veillard4432df22003-09-28 18:58:27 +00003086#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003087/**
3088 * xmlValidateNotationUse:
3089 * @ctxt: the validation context
3090 * @doc: the document
3091 * @notationName: the notation name to check
3092 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003093 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003094 * - [ VC: Notation Declared ]
3095 *
3096 * returns 1 if valid or 0 otherwise
3097 */
3098
3099int
3100xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3101 const xmlChar *notationName) {
3102 xmlNotationPtr notaDecl;
3103 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3104
3105 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3106 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3107 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3108
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003109 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003110 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3111 "NOTATION %s is not declared\n",
3112 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003113 return(0);
3114 }
3115 return(1);
3116}
Daniel Veillard4432df22003-09-28 18:58:27 +00003117#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003118
3119/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003120 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003121 * @doc: the document
3122 * @name: the element name
3123 *
3124 * Search in the DtDs whether an element accept Mixed content (or ANY)
3125 * basically if it is supposed to accept text childs
3126 *
3127 * returns 0 if no, 1 if yes, and -1 if no element description is available
3128 */
3129
3130int
3131xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3132 xmlElementPtr elemDecl;
3133
3134 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3135
3136 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3137 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3138 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3139 if (elemDecl == NULL) return(-1);
3140 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003141 case XML_ELEMENT_TYPE_UNDEFINED:
3142 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003143 case XML_ELEMENT_TYPE_ELEMENT:
3144 return(0);
3145 case XML_ELEMENT_TYPE_EMPTY:
3146 /*
3147 * return 1 for EMPTY since we want VC error to pop up
3148 * on <empty> </empty> for example
3149 */
3150 case XML_ELEMENT_TYPE_ANY:
3151 case XML_ELEMENT_TYPE_MIXED:
3152 return(1);
3153 }
3154 return(1);
3155}
3156
Daniel Veillard4432df22003-09-28 18:58:27 +00003157#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003158/**
3159 * xmlValidateNameValue:
3160 * @value: an Name value
3161 *
3162 * Validate that the given value match Name production
3163 *
3164 * returns 1 if valid or 0 otherwise
3165 */
3166
Daniel Veillard9b731d72002-04-14 12:56:08 +00003167int
Owen Taylor3473f882001-02-23 17:55:21 +00003168xmlValidateNameValue(const xmlChar *value) {
3169 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003170 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003171
3172 if (value == NULL) return(0);
3173 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003174 val = xmlStringCurrentChar(NULL, cur, &len);
3175 cur += len;
3176 if (!IS_LETTER(val) && (val != '_') &&
3177 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003178 return(0);
3179 }
3180
Daniel Veillardd8224e02002-01-13 15:43:22 +00003181 val = xmlStringCurrentChar(NULL, cur, &len);
3182 cur += len;
3183 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3184 (val == '.') || (val == '-') ||
3185 (val == '_') || (val == ':') ||
3186 (IS_COMBINING(val)) ||
3187 (IS_EXTENDER(val))) {
3188 val = xmlStringCurrentChar(NULL, cur, &len);
3189 cur += len;
3190 }
Owen Taylor3473f882001-02-23 17:55:21 +00003191
Daniel Veillardd8224e02002-01-13 15:43:22 +00003192 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003193
3194 return(1);
3195}
3196
3197/**
3198 * xmlValidateNamesValue:
3199 * @value: an Names value
3200 *
3201 * Validate that the given value match Names production
3202 *
3203 * returns 1 if valid or 0 otherwise
3204 */
3205
Daniel Veillard9b731d72002-04-14 12:56:08 +00003206int
Owen Taylor3473f882001-02-23 17:55:21 +00003207xmlValidateNamesValue(const xmlChar *value) {
3208 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003209 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003210
3211 if (value == NULL) return(0);
3212 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003213 val = xmlStringCurrentChar(NULL, cur, &len);
3214 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003215
Daniel Veillardd8224e02002-01-13 15:43:22 +00003216 if (!IS_LETTER(val) && (val != '_') &&
3217 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003218 return(0);
3219 }
3220
Daniel Veillardd8224e02002-01-13 15:43:22 +00003221 val = xmlStringCurrentChar(NULL, cur, &len);
3222 cur += len;
3223 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3224 (val == '.') || (val == '-') ||
3225 (val == '_') || (val == ':') ||
3226 (IS_COMBINING(val)) ||
3227 (IS_EXTENDER(val))) {
3228 val = xmlStringCurrentChar(NULL, cur, &len);
3229 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003230 }
3231
Daniel Veillardd8224e02002-01-13 15:43:22 +00003232 while (IS_BLANK(val)) {
3233 while (IS_BLANK(val)) {
3234 val = xmlStringCurrentChar(NULL, cur, &len);
3235 cur += len;
3236 }
3237
3238 if (!IS_LETTER(val) && (val != '_') &&
3239 (val != ':')) {
3240 return(0);
3241 }
3242 val = xmlStringCurrentChar(NULL, cur, &len);
3243 cur += len;
3244
3245 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3246 (val == '.') || (val == '-') ||
3247 (val == '_') || (val == ':') ||
3248 (IS_COMBINING(val)) ||
3249 (IS_EXTENDER(val))) {
3250 val = xmlStringCurrentChar(NULL, cur, &len);
3251 cur += len;
3252 }
3253 }
3254
3255 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003256
3257 return(1);
3258}
3259
3260/**
3261 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003262 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003263 *
3264 * Validate that the given value match Nmtoken production
3265 *
3266 * [ VC: Name Token ]
3267 *
3268 * returns 1 if valid or 0 otherwise
3269 */
3270
Daniel Veillard9b731d72002-04-14 12:56:08 +00003271int
Owen Taylor3473f882001-02-23 17:55:21 +00003272xmlValidateNmtokenValue(const xmlChar *value) {
3273 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003274 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003275
3276 if (value == NULL) return(0);
3277 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003278 val = xmlStringCurrentChar(NULL, cur, &len);
3279 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003280
Daniel Veillardd8224e02002-01-13 15:43:22 +00003281 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3282 (val != '.') && (val != '-') &&
3283 (val != '_') && (val != ':') &&
3284 (!IS_COMBINING(val)) &&
3285 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003286 return(0);
3287
Daniel Veillardd8224e02002-01-13 15:43:22 +00003288 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3289 (val == '.') || (val == '-') ||
3290 (val == '_') || (val == ':') ||
3291 (IS_COMBINING(val)) ||
3292 (IS_EXTENDER(val))) {
3293 val = xmlStringCurrentChar(NULL, cur, &len);
3294 cur += len;
3295 }
Owen Taylor3473f882001-02-23 17:55:21 +00003296
Daniel Veillardd8224e02002-01-13 15:43:22 +00003297 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003298
3299 return(1);
3300}
3301
3302/**
3303 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003304 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003305 *
3306 * Validate that the given value match Nmtokens production
3307 *
3308 * [ VC: Name Token ]
3309 *
3310 * returns 1 if valid or 0 otherwise
3311 */
3312
Daniel Veillard9b731d72002-04-14 12:56:08 +00003313int
Owen Taylor3473f882001-02-23 17:55:21 +00003314xmlValidateNmtokensValue(const xmlChar *value) {
3315 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003316 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003317
3318 if (value == NULL) return(0);
3319 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003320 val = xmlStringCurrentChar(NULL, cur, &len);
3321 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003322
Daniel Veillardd8224e02002-01-13 15:43:22 +00003323 while (IS_BLANK(val)) {
3324 val = xmlStringCurrentChar(NULL, cur, &len);
3325 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003326 }
3327
Daniel Veillardd8224e02002-01-13 15:43:22 +00003328 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3329 (val != '.') && (val != '-') &&
3330 (val != '_') && (val != ':') &&
3331 (!IS_COMBINING(val)) &&
3332 (!IS_EXTENDER(val)))
3333 return(0);
3334
3335 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3336 (val == '.') || (val == '-') ||
3337 (val == '_') || (val == ':') ||
3338 (IS_COMBINING(val)) ||
3339 (IS_EXTENDER(val))) {
3340 val = xmlStringCurrentChar(NULL, cur, &len);
3341 cur += len;
3342 }
3343
3344 while (IS_BLANK(val)) {
3345 while (IS_BLANK(val)) {
3346 val = xmlStringCurrentChar(NULL, cur, &len);
3347 cur += len;
3348 }
3349 if (val == 0) return(1);
3350
3351 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3352 (val != '.') && (val != '-') &&
3353 (val != '_') && (val != ':') &&
3354 (!IS_COMBINING(val)) &&
3355 (!IS_EXTENDER(val)))
3356 return(0);
3357
3358 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3359 (val == '.') || (val == '-') ||
3360 (val == '_') || (val == ':') ||
3361 (IS_COMBINING(val)) ||
3362 (IS_EXTENDER(val))) {
3363 val = xmlStringCurrentChar(NULL, cur, &len);
3364 cur += len;
3365 }
3366 }
3367
3368 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003369
3370 return(1);
3371}
3372
3373/**
3374 * xmlValidateNotationDecl:
3375 * @ctxt: the validation context
3376 * @doc: a document instance
3377 * @nota: a notation definition
3378 *
3379 * Try to validate a single notation definition
3380 * basically it does the following checks as described by the
3381 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003382 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003383 * But this function get called anyway ...
3384 *
3385 * returns 1 if valid or 0 otherwise
3386 */
3387
3388int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003389xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3390 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003391 int ret = 1;
3392
3393 return(ret);
3394}
3395
3396/**
3397 * xmlValidateAttributeValue:
3398 * @type: an attribute type
3399 * @value: an attribute value
3400 *
3401 * Validate that the given attribute value match the proper production
3402 *
3403 * [ VC: ID ]
3404 * Values of type ID must match the Name production....
3405 *
3406 * [ VC: IDREF ]
3407 * Values of type IDREF must match the Name production, and values
3408 * of type IDREFS must match Names ...
3409 *
3410 * [ VC: Entity Name ]
3411 * Values of type ENTITY must match the Name production, values
3412 * of type ENTITIES must match Names ...
3413 *
3414 * [ VC: Name Token ]
3415 * Values of type NMTOKEN must match the Nmtoken production; values
3416 * of type NMTOKENS must match Nmtokens.
3417 *
3418 * returns 1 if valid or 0 otherwise
3419 */
3420
3421int
3422xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3423 switch (type) {
3424 case XML_ATTRIBUTE_ENTITIES:
3425 case XML_ATTRIBUTE_IDREFS:
3426 return(xmlValidateNamesValue(value));
3427 case XML_ATTRIBUTE_ENTITY:
3428 case XML_ATTRIBUTE_IDREF:
3429 case XML_ATTRIBUTE_ID:
3430 case XML_ATTRIBUTE_NOTATION:
3431 return(xmlValidateNameValue(value));
3432 case XML_ATTRIBUTE_NMTOKENS:
3433 case XML_ATTRIBUTE_ENUMERATION:
3434 return(xmlValidateNmtokensValue(value));
3435 case XML_ATTRIBUTE_NMTOKEN:
3436 return(xmlValidateNmtokenValue(value));
3437 case XML_ATTRIBUTE_CDATA:
3438 break;
3439 }
3440 return(1);
3441}
3442
3443/**
3444 * xmlValidateAttributeValue2:
3445 * @ctxt: the validation context
3446 * @doc: the document
3447 * @name: the attribute name (used for error reporting only)
3448 * @type: the attribute type
3449 * @value: the attribute value
3450 *
3451 * Validate that the given attribute value match a given type.
3452 * This typically cannot be done before having finished parsing
3453 * the subsets.
3454 *
3455 * [ VC: IDREF ]
3456 * Values of type IDREF must match one of the declared IDs
3457 * Values of type IDREFS must match a sequence of the declared IDs
3458 * each Name must match the value of an ID attribute on some element
3459 * in the XML document; i.e. IDREF values must match the value of
3460 * some ID attribute
3461 *
3462 * [ VC: Entity Name ]
3463 * Values of type ENTITY must match one declared entity
3464 * Values of type ENTITIES must match a sequence of declared entities
3465 *
3466 * [ VC: Notation Attributes ]
3467 * all notation names in the declaration must be declared.
3468 *
3469 * returns 1 if valid or 0 otherwise
3470 */
3471
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003472static int
Owen Taylor3473f882001-02-23 17:55:21 +00003473xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3474 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3475 int ret = 1;
3476 switch (type) {
3477 case XML_ATTRIBUTE_IDREFS:
3478 case XML_ATTRIBUTE_IDREF:
3479 case XML_ATTRIBUTE_ID:
3480 case XML_ATTRIBUTE_NMTOKENS:
3481 case XML_ATTRIBUTE_ENUMERATION:
3482 case XML_ATTRIBUTE_NMTOKEN:
3483 case XML_ATTRIBUTE_CDATA:
3484 break;
3485 case XML_ATTRIBUTE_ENTITY: {
3486 xmlEntityPtr ent;
3487
3488 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003489 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003490 if ((ent == NULL) && (doc->standalone == 1)) {
3491 doc->standalone = 0;
3492 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003493 }
Owen Taylor3473f882001-02-23 17:55:21 +00003494 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003495 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3496 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003497 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003498 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003499 ret = 0;
3500 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003501 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3502 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003503 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003504 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003505 ret = 0;
3506 }
3507 break;
3508 }
3509 case XML_ATTRIBUTE_ENTITIES: {
3510 xmlChar *dup, *nam = NULL, *cur, save;
3511 xmlEntityPtr ent;
3512
3513 dup = xmlStrdup(value);
3514 if (dup == NULL)
3515 return(0);
3516 cur = dup;
3517 while (*cur != 0) {
3518 nam = cur;
3519 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3520 save = *cur;
3521 *cur = 0;
3522 ent = xmlGetDocEntity(doc, nam);
3523 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003524 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3525 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003526 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003527 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003528 ret = 0;
3529 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003530 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3531 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003532 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003533 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003534 ret = 0;
3535 }
3536 if (save == 0)
3537 break;
3538 *cur = save;
3539 while (IS_BLANK(*cur)) cur++;
3540 }
3541 xmlFree(dup);
3542 break;
3543 }
3544 case XML_ATTRIBUTE_NOTATION: {
3545 xmlNotationPtr nota;
3546
3547 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3548 if ((nota == NULL) && (doc->extSubset != NULL))
3549 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3550
3551 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003552 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3553 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003554 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003555 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003556 ret = 0;
3557 }
3558 break;
3559 }
3560 }
3561 return(ret);
3562}
3563
3564/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003565 * xmlValidCtxtNormalizeAttributeValue:
3566 * @ctxt: the validation context
3567 * @doc: the document
3568 * @elem: the parent
3569 * @name: the attribute name
3570 * @value: the attribute value
3571 * @ctxt: the validation context or NULL
3572 *
3573 * Does the validation related extra step of the normalization of attribute
3574 * values:
3575 *
3576 * If the declared value is not CDATA, then the XML processor must further
3577 * process the normalized attribute value by discarding any leading and
3578 * trailing space (#x20) characters, and by replacing sequences of space
3579 * (#x20) characters by single space (#x20) character.
3580 *
3581 * Also check VC: Standalone Document Declaration in P32, and update
3582 * ctxt->valid accordingly
3583 *
3584 * returns a new normalized string if normalization is needed, NULL otherwise
3585 * the caller must free the returned value.
3586 */
3587
3588xmlChar *
3589xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3590 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3591 xmlChar *ret, *dst;
3592 const xmlChar *src;
3593 xmlAttributePtr attrDecl = NULL;
3594 int extsubset = 0;
3595
3596 if (doc == NULL) return(NULL);
3597 if (elem == NULL) return(NULL);
3598 if (name == NULL) return(NULL);
3599 if (value == NULL) return(NULL);
3600
3601 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003602 xmlChar fn[50];
3603 xmlChar *fullname;
3604
3605 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3606 if (fullname == NULL)
3607 return(0);
3608 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003609 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003610 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003611 if (attrDecl != NULL)
3612 extsubset = 1;
3613 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003614 if ((fullname != fn) && (fullname != elem->name))
3615 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003616 }
3617 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3618 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3619 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3620 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3621 if (attrDecl != NULL)
3622 extsubset = 1;
3623 }
3624
3625 if (attrDecl == NULL)
3626 return(NULL);
3627 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3628 return(NULL);
3629
3630 ret = xmlStrdup(value);
3631 if (ret == NULL)
3632 return(NULL);
3633 src = value;
3634 dst = ret;
3635 while (*src == 0x20) src++;
3636 while (*src != 0) {
3637 if (*src == 0x20) {
3638 while (*src == 0x20) src++;
3639 if (*src != 0)
3640 *dst++ = 0x20;
3641 } else {
3642 *dst++ = *src++;
3643 }
3644 }
3645 *dst = 0;
3646 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003647 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003648"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003649 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003650 ctxt->valid = 0;
3651 }
3652 return(ret);
3653}
3654
3655/**
Owen Taylor3473f882001-02-23 17:55:21 +00003656 * xmlValidNormalizeAttributeValue:
3657 * @doc: the document
3658 * @elem: the parent
3659 * @name: the attribute name
3660 * @value: the attribute value
3661 *
3662 * Does the validation related extra step of the normalization of attribute
3663 * values:
3664 *
3665 * If the declared value is not CDATA, then the XML processor must further
3666 * process the normalized attribute value by discarding any leading and
3667 * trailing space (#x20) characters, and by replacing sequences of space
3668 * (#x20) characters by single space (#x20) character.
3669 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003670 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003671 * the caller must free the returned value.
3672 */
3673
3674xmlChar *
3675xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3676 const xmlChar *name, const xmlChar *value) {
3677 xmlChar *ret, *dst;
3678 const xmlChar *src;
3679 xmlAttributePtr attrDecl = NULL;
3680
3681 if (doc == NULL) return(NULL);
3682 if (elem == NULL) return(NULL);
3683 if (name == NULL) return(NULL);
3684 if (value == NULL) return(NULL);
3685
3686 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003687 xmlChar fn[50];
3688 xmlChar *fullname;
3689
3690 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3691 if (fullname == NULL)
3692 return(0);
3693 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003694 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003695 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3696 if ((fullname != fn) && (fullname != elem->name))
3697 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003698 }
3699 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3700 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3701 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3702
3703 if (attrDecl == NULL)
3704 return(NULL);
3705 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3706 return(NULL);
3707
3708 ret = xmlStrdup(value);
3709 if (ret == NULL)
3710 return(NULL);
3711 src = value;
3712 dst = ret;
3713 while (*src == 0x20) src++;
3714 while (*src != 0) {
3715 if (*src == 0x20) {
3716 while (*src == 0x20) src++;
3717 if (*src != 0)
3718 *dst++ = 0x20;
3719 } else {
3720 *dst++ = *src++;
3721 }
3722 }
3723 *dst = 0;
3724 return(ret);
3725}
3726
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003727static void
Owen Taylor3473f882001-02-23 17:55:21 +00003728xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003729 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003730 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3731}
3732
3733/**
3734 * xmlValidateAttributeDecl:
3735 * @ctxt: the validation context
3736 * @doc: a document instance
3737 * @attr: an attribute definition
3738 *
3739 * Try to validate a single attribute definition
3740 * basically it does the following checks as described by the
3741 * XML-1.0 recommendation:
3742 * - [ VC: Attribute Default Legal ]
3743 * - [ VC: Enumeration ]
3744 * - [ VC: ID Attribute Default ]
3745 *
3746 * The ID/IDREF uniqueness and matching are done separately
3747 *
3748 * returns 1 if valid or 0 otherwise
3749 */
3750
3751int
3752xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3753 xmlAttributePtr attr) {
3754 int ret = 1;
3755 int val;
3756 CHECK_DTD;
3757 if(attr == NULL) return(1);
3758
3759 /* Attribute Default Legal */
3760 /* Enumeration */
3761 if (attr->defaultValue != NULL) {
3762 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3763 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003764 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003765 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003766 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003767 }
3768 ret &= val;
3769 }
3770
3771 /* ID Attribute Default */
3772 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3773 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3774 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003775 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003776 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003777 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003778 ret = 0;
3779 }
3780
3781 /* One ID per Element Type */
3782 if (attr->atype == XML_ATTRIBUTE_ID) {
3783 int nbId;
3784
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003785 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00003786 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3787 attr->elem);
3788 if (elem != NULL) {
3789 nbId = xmlScanIDAttributeDecl(NULL, elem);
3790 } else {
3791 xmlAttributeTablePtr table;
3792
3793 /*
3794 * The attribute may be declared in the internal subset and the
3795 * element in the external subset.
3796 */
3797 nbId = 0;
3798 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3799 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3800 xmlValidateAttributeIdCallback, &nbId);
3801 }
3802 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003803
3804 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003805 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3806 attr->elem, nbId, attr->name);
3807 } else if (doc->extSubset != NULL) {
3808 int extId = 0;
3809 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3810 if (elem != NULL) {
3811 extId = xmlScanIDAttributeDecl(NULL, elem);
3812 }
3813 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003814 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003815 "Element %s has %d ID attribute defined in the external subset : %s\n",
3816 attr->elem, extId, attr->name);
3817 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003818 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003819"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003820 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003821 }
3822 }
3823 }
3824
3825 /* Validity Constraint: Enumeration */
3826 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3827 xmlEnumerationPtr tree = attr->tree;
3828 while (tree != NULL) {
3829 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3830 tree = tree->next;
3831 }
3832 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003833 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003834"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003835 attr->defaultValue, attr->name, attr->elem);
3836 ret = 0;
3837 }
3838 }
3839
3840 return(ret);
3841}
3842
3843/**
3844 * xmlValidateElementDecl:
3845 * @ctxt: the validation context
3846 * @doc: a document instance
3847 * @elem: an element definition
3848 *
3849 * Try to validate a single element definition
3850 * basically it does the following checks as described by the
3851 * XML-1.0 recommendation:
3852 * - [ VC: One ID per Element Type ]
3853 * - [ VC: No Duplicate Types ]
3854 * - [ VC: Unique Element Type Declaration ]
3855 *
3856 * returns 1 if valid or 0 otherwise
3857 */
3858
3859int
3860xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3861 xmlElementPtr elem) {
3862 int ret = 1;
3863 xmlElementPtr tst;
3864
3865 CHECK_DTD;
3866
3867 if (elem == NULL) return(1);
3868
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003869#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00003870#ifdef LIBXML_REGEXP_ENABLED
3871 /* Build the regexp associated to the content model */
3872 ret = xmlValidBuildContentModel(ctxt, elem);
3873#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003874#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00003875
Owen Taylor3473f882001-02-23 17:55:21 +00003876 /* No Duplicate Types */
3877 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3878 xmlElementContentPtr cur, next;
3879 const xmlChar *name;
3880
3881 cur = elem->content;
3882 while (cur != NULL) {
3883 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3884 if (cur->c1 == NULL) break;
3885 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3886 name = cur->c1->name;
3887 next = cur->c2;
3888 while (next != NULL) {
3889 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00003890 if ((xmlStrEqual(next->name, name)) &&
3891 (xmlStrEqual(next->prefix, cur->prefix))) {
3892 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003893 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00003894 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003895 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003896 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003897 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003898 "Definition of %s has duplicate references of %s:%s\n",
3899 elem->name, cur->prefix, name);
3900 }
Owen Taylor3473f882001-02-23 17:55:21 +00003901 ret = 0;
3902 }
3903 break;
3904 }
3905 if (next->c1 == NULL) break;
3906 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00003907 if ((xmlStrEqual(next->c1->name, name)) &&
3908 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
3909 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003910 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003911 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003912 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003913 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003914 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003915 "Definition of %s has duplicate references to %s:%s\n",
3916 elem->name, cur->prefix, name);
3917 }
Owen Taylor3473f882001-02-23 17:55:21 +00003918 ret = 0;
3919 }
3920 next = next->c2;
3921 }
3922 }
3923 cur = cur->c2;
3924 }
3925 }
3926
3927 /* VC: Unique Element Type Declaration */
3928 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003929 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00003930 ((tst->prefix == elem->prefix) ||
3931 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00003932 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003933 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
3934 "Redefinition of element %s\n",
3935 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003936 ret = 0;
3937 }
3938 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003939 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00003940 ((tst->prefix == elem->prefix) ||
3941 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00003942 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003943 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
3944 "Redefinition of element %s\n",
3945 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003946 ret = 0;
3947 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00003948 /* One ID per Element Type
3949 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00003950 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3951 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00003952 } */
Owen Taylor3473f882001-02-23 17:55:21 +00003953 return(ret);
3954}
3955
3956/**
3957 * xmlValidateOneAttribute:
3958 * @ctxt: the validation context
3959 * @doc: a document instance
3960 * @elem: an element instance
3961 * @attr: an attribute instance
3962 * @value: the attribute value (without entities processing)
3963 *
3964 * Try to validate a single attribute for an element
3965 * basically it does the following checks as described by the
3966 * XML-1.0 recommendation:
3967 * - [ VC: Attribute Value Type ]
3968 * - [ VC: Fixed Attribute Default ]
3969 * - [ VC: Entity Name ]
3970 * - [ VC: Name Token ]
3971 * - [ VC: ID ]
3972 * - [ VC: IDREF ]
3973 * - [ VC: Entity Name ]
3974 * - [ VC: Notation Attributes ]
3975 *
3976 * The ID/IDREF uniqueness and matching are done separately
3977 *
3978 * returns 1 if valid or 0 otherwise
3979 */
3980
3981int
3982xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00003983 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
3984{
Owen Taylor3473f882001-02-23 17:55:21 +00003985 xmlAttributePtr attrDecl = NULL;
3986 int val;
3987 int ret = 1;
3988
3989 CHECK_DTD;
3990 if ((elem == NULL) || (elem->name == NULL)) return(0);
3991 if ((attr == NULL) || (attr->name == NULL)) return(0);
3992
3993 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003994 xmlChar fn[50];
3995 xmlChar *fullname;
3996
3997 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3998 if (fullname == NULL)
3999 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004000 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004001 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004002 attr->name, attr->ns->prefix);
4003 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004004 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004005 attr->name, attr->ns->prefix);
4006 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004007 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004008 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4009 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004010 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004011 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004012 if ((fullname != fn) && (fullname != elem->name))
4013 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004014 }
4015 if (attrDecl == NULL) {
4016 if (attr->ns != NULL) {
4017 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4018 attr->name, attr->ns->prefix);
4019 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4020 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4021 attr->name, attr->ns->prefix);
4022 } else {
4023 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4024 elem->name, attr->name);
4025 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4026 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4027 elem->name, attr->name);
4028 }
4029 }
4030
4031
4032 /* Validity Constraint: Attribute Value Type */
4033 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004034 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004035 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004036 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004037 return(0);
4038 }
4039 attr->atype = attrDecl->atype;
4040
4041 val = xmlValidateAttributeValue(attrDecl->atype, value);
4042 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004043 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004044 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004045 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004046 ret = 0;
4047 }
4048
4049 /* Validity constraint: Fixed Attribute Default */
4050 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4051 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004052 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004053 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004054 attr->name, elem->name, attrDecl->defaultValue);
4055 ret = 0;
4056 }
4057 }
4058
4059 /* Validity Constraint: ID uniqueness */
4060 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4061 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4062 ret = 0;
4063 }
4064
4065 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4066 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4067 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4068 ret = 0;
4069 }
4070
4071 /* Validity Constraint: Notation Attributes */
4072 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4073 xmlEnumerationPtr tree = attrDecl->tree;
4074 xmlNotationPtr nota;
4075
4076 /* First check that the given NOTATION was declared */
4077 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4078 if (nota == NULL)
4079 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4080
4081 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004082 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004083 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004084 value, attr->name, elem->name);
4085 ret = 0;
4086 }
4087
4088 /* Second, verify that it's among the list */
4089 while (tree != NULL) {
4090 if (xmlStrEqual(tree->name, value)) break;
4091 tree = tree->next;
4092 }
4093 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004094 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004095"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004096 value, attr->name, elem->name);
4097 ret = 0;
4098 }
4099 }
4100
4101 /* Validity Constraint: Enumeration */
4102 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4103 xmlEnumerationPtr tree = attrDecl->tree;
4104 while (tree != NULL) {
4105 if (xmlStrEqual(tree->name, value)) break;
4106 tree = tree->next;
4107 }
4108 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004109 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004110 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004111 value, attr->name, elem->name);
4112 ret = 0;
4113 }
4114 }
4115
4116 /* Fixed Attribute Default */
4117 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4118 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004119 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004120 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004121 attr->name, elem->name, attrDecl->defaultValue);
4122 ret = 0;
4123 }
4124
4125 /* Extra check for the attribute value */
4126 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4127 attrDecl->atype, value);
4128
4129 return(ret);
4130}
4131
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004132/**
4133 * xmlValidateOneNamespace:
4134 * @ctxt: the validation context
4135 * @doc: a document instance
4136 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004137 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004138 * @ns: an namespace declaration instance
4139 * @value: the attribute value (without entities processing)
4140 *
4141 * Try to validate a single namespace declaration for an element
4142 * basically it does the following checks as described by the
4143 * XML-1.0 recommendation:
4144 * - [ VC: Attribute Value Type ]
4145 * - [ VC: Fixed Attribute Default ]
4146 * - [ VC: Entity Name ]
4147 * - [ VC: Name Token ]
4148 * - [ VC: ID ]
4149 * - [ VC: IDREF ]
4150 * - [ VC: Entity Name ]
4151 * - [ VC: Notation Attributes ]
4152 *
4153 * The ID/IDREF uniqueness and matching are done separately
4154 *
4155 * returns 1 if valid or 0 otherwise
4156 */
4157
4158int
4159xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4160xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4161 /* xmlElementPtr elemDecl; */
4162 xmlAttributePtr attrDecl = NULL;
4163 int val;
4164 int ret = 1;
4165
4166 CHECK_DTD;
4167 if ((elem == NULL) || (elem->name == NULL)) return(0);
4168 if ((ns == NULL) || (ns->href == NULL)) return(0);
4169
4170 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004171 xmlChar fn[50];
4172 xmlChar *fullname;
4173
4174 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4175 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004176 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004177 return(0);
4178 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004179 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004180 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004181 ns->prefix, BAD_CAST "xmlns");
4182 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004183 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004184 ns->prefix, BAD_CAST "xmlns");
4185 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004186 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004187 BAD_CAST "xmlns");
4188 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004189 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004190 BAD_CAST "xmlns");
4191 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004192 if ((fullname != fn) && (fullname != elem->name))
4193 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004194 }
4195 if (attrDecl == NULL) {
4196 if (ns->prefix != NULL) {
4197 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4198 ns->prefix, BAD_CAST "xmlns");
4199 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4200 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4201 ns->prefix, BAD_CAST "xmlns");
4202 } else {
4203 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4204 elem->name, BAD_CAST "xmlns");
4205 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4206 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4207 elem->name, BAD_CAST "xmlns");
4208 }
4209 }
4210
4211
4212 /* Validity Constraint: Attribute Value Type */
4213 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004214 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004215 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004216 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004217 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004218 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004219 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004220 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004221 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004222 }
4223 return(0);
4224 }
4225
4226 val = xmlValidateAttributeValue(attrDecl->atype, value);
4227 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004228 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004229 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004230 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004231 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004232 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004233 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004234 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004235 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004236 }
4237 ret = 0;
4238 }
4239
4240 /* Validity constraint: Fixed Attribute Default */
4241 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4242 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004243 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004244 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004245 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4246 ns->prefix, elem->name, attrDecl->defaultValue);
4247 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004248 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004249 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004250 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004251 }
4252 ret = 0;
4253 }
4254 }
4255
4256 /* Validity Constraint: ID uniqueness */
4257 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4258 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4259 ret = 0;
4260 }
4261
4262 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4263 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4264 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4265 ret = 0;
4266 }
4267
4268 /* Validity Constraint: Notation Attributes */
4269 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4270 xmlEnumerationPtr tree = attrDecl->tree;
4271 xmlNotationPtr nota;
4272
4273 /* First check that the given NOTATION was declared */
4274 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4275 if (nota == NULL)
4276 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4277
4278 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004279 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004280 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004281 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4282 value, ns->prefix, elem->name);
4283 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004284 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004285 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004286 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004287 }
4288 ret = 0;
4289 }
4290
4291 /* Second, verify that it's among the list */
4292 while (tree != NULL) {
4293 if (xmlStrEqual(tree->name, value)) break;
4294 tree = tree->next;
4295 }
4296 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004297 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004298 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004299"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4300 value, ns->prefix, elem->name);
4301 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004302 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004303"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004304 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004305 }
4306 ret = 0;
4307 }
4308 }
4309
4310 /* Validity Constraint: Enumeration */
4311 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4312 xmlEnumerationPtr tree = attrDecl->tree;
4313 while (tree != NULL) {
4314 if (xmlStrEqual(tree->name, value)) break;
4315 tree = tree->next;
4316 }
4317 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004318 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004319 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004320"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4321 value, ns->prefix, elem->name);
4322 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004323 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004324"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004325 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004326 }
4327 ret = 0;
4328 }
4329 }
4330
4331 /* Fixed Attribute Default */
4332 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4333 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004334 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004335 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004336 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4337 ns->prefix, elem->name, attrDecl->defaultValue);
4338 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004339 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004340 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004341 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004342 }
4343 ret = 0;
4344 }
4345
4346 /* Extra check for the attribute value */
4347 if (ns->prefix != NULL) {
4348 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4349 attrDecl->atype, value);
4350 } else {
4351 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4352 attrDecl->atype, value);
4353 }
4354
4355 return(ret);
4356}
4357
Daniel Veillard118aed72002-09-24 14:13:13 +00004358#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004359/**
4360 * xmlValidateSkipIgnorable:
4361 * @ctxt: the validation context
4362 * @child: the child list
4363 *
4364 * Skip ignorable elements w.r.t. the validation process
4365 *
4366 * returns the first element to consider for validation of the content model
4367 */
4368
4369static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004370xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004371 while (child != NULL) {
4372 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004373 /* These things are ignored (skipped) during validation. */
4374 case XML_PI_NODE:
4375 case XML_COMMENT_NODE:
4376 case XML_XINCLUDE_START:
4377 case XML_XINCLUDE_END:
4378 child = child->next;
4379 break;
4380 case XML_TEXT_NODE:
4381 if (xmlIsBlankNode(child))
4382 child = child->next;
4383 else
4384 return(child);
4385 break;
4386 /* keep current node */
4387 default:
4388 return(child);
4389 }
4390 }
4391 return(child);
4392}
4393
4394/**
4395 * xmlValidateElementType:
4396 * @ctxt: the validation context
4397 *
4398 * Try to validate the content model of an element internal function
4399 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004400 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4401 * reference is found and -3 if the validation succeeded but
4402 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004403 */
4404
4405static int
4406xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004407 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004408 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004409
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004410 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004411 if ((NODE == NULL) && (CONT == NULL))
4412 return(1);
4413 if ((NODE == NULL) &&
4414 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4415 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4416 return(1);
4417 }
4418 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004419 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004420 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004421
4422 /*
4423 * We arrive here when more states need to be examined
4424 */
4425cont:
4426
4427 /*
4428 * We just recovered from a rollback generated by a possible
4429 * epsilon transition, go directly to the analysis phase
4430 */
4431 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004432 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004433 DEBUG_VALID_STATE(NODE, CONT)
4434 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004435 goto analyze;
4436 }
4437
4438 DEBUG_VALID_STATE(NODE, CONT)
4439 /*
4440 * we may have to save a backup state here. This is the equivalent
4441 * of handling epsilon transition in NFAs.
4442 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004443 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004444 ((CONT->parent == NULL) ||
4445 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004446 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004447 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004448 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004449 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004450 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4451 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004452 }
4453
4454
4455 /*
4456 * Check first if the content matches
4457 */
4458 switch (CONT->type) {
4459 case XML_ELEMENT_CONTENT_PCDATA:
4460 if (NODE == NULL) {
4461 DEBUG_VALID_MSG("pcdata failed no node");
4462 ret = 0;
4463 break;
4464 }
4465 if (NODE->type == XML_TEXT_NODE) {
4466 DEBUG_VALID_MSG("pcdata found, skip to next");
4467 /*
4468 * go to next element in the content model
4469 * skipping ignorable elems
4470 */
4471 do {
4472 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004473 NODE = xmlValidateSkipIgnorable(NODE);
4474 if ((NODE != NULL) &&
4475 (NODE->type == XML_ENTITY_REF_NODE))
4476 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004477 } while ((NODE != NULL) &&
4478 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004479 (NODE->type != XML_TEXT_NODE) &&
4480 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004481 ret = 1;
4482 break;
4483 } else {
4484 DEBUG_VALID_MSG("pcdata failed");
4485 ret = 0;
4486 break;
4487 }
4488 break;
4489 case XML_ELEMENT_CONTENT_ELEMENT:
4490 if (NODE == NULL) {
4491 DEBUG_VALID_MSG("element failed no node");
4492 ret = 0;
4493 break;
4494 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004495 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4496 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004497 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004498 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4499 ret = (CONT->prefix == NULL);
4500 } else if (CONT->prefix == NULL) {
4501 ret = 0;
4502 } else {
4503 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4504 }
4505 }
4506 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004507 DEBUG_VALID_MSG("element found, skip to next");
4508 /*
4509 * go to next element in the content model
4510 * skipping ignorable elems
4511 */
4512 do {
4513 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004514 NODE = xmlValidateSkipIgnorable(NODE);
4515 if ((NODE != NULL) &&
4516 (NODE->type == XML_ENTITY_REF_NODE))
4517 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004518 } while ((NODE != NULL) &&
4519 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004520 (NODE->type != XML_TEXT_NODE) &&
4521 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004522 } else {
4523 DEBUG_VALID_MSG("element failed");
4524 ret = 0;
4525 break;
4526 }
4527 break;
4528 case XML_ELEMENT_CONTENT_OR:
4529 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004530 * Small optimization.
4531 */
4532 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4533 if ((NODE == NULL) ||
4534 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4535 DEPTH++;
4536 CONT = CONT->c2;
4537 goto cont;
4538 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004539 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4540 ret = (CONT->c1->prefix == NULL);
4541 } else if (CONT->c1->prefix == NULL) {
4542 ret = 0;
4543 } else {
4544 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4545 }
4546 if (ret == 0) {
4547 DEPTH++;
4548 CONT = CONT->c2;
4549 goto cont;
4550 }
Daniel Veillard85349052001-04-20 13:48:21 +00004551 }
4552
4553 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004554 * save the second branch 'or' branch
4555 */
4556 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004557 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4558 OCCURS, ROLLBACK_OR) < 0)
4559 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004560 DEPTH++;
4561 CONT = CONT->c1;
4562 goto cont;
4563 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004564 /*
4565 * Small optimization.
4566 */
4567 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4568 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4569 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4570 if ((NODE == NULL) ||
4571 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4572 DEPTH++;
4573 CONT = CONT->c2;
4574 goto cont;
4575 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004576 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4577 ret = (CONT->c1->prefix == NULL);
4578 } else if (CONT->c1->prefix == NULL) {
4579 ret = 0;
4580 } else {
4581 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4582 }
4583 if (ret == 0) {
4584 DEPTH++;
4585 CONT = CONT->c2;
4586 goto cont;
4587 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004588 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004589 DEPTH++;
4590 CONT = CONT->c1;
4591 goto cont;
4592 }
4593
4594 /*
4595 * At this point handle going up in the tree
4596 */
4597 if (ret == -1) {
4598 DEBUG_VALID_MSG("error found returning");
4599 return(ret);
4600 }
4601analyze:
4602 while (CONT != NULL) {
4603 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004604 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004605 * this level.
4606 */
4607 if (ret == 0) {
4608 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004609 xmlNodePtr cur;
4610
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004611 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004612 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004613 DEBUG_VALID_MSG("Once branch failed, rollback");
4614 if (vstateVPop(ctxt) < 0 ) {
4615 DEBUG_VALID_MSG("exhaustion, failed");
4616 return(0);
4617 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004618 if (cur != ctxt->vstate->node)
4619 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004620 goto cont;
4621 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004622 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004623 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004624 DEBUG_VALID_MSG("Plus branch failed, rollback");
4625 if (vstateVPop(ctxt) < 0 ) {
4626 DEBUG_VALID_MSG("exhaustion, failed");
4627 return(0);
4628 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004629 if (cur != ctxt->vstate->node)
4630 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004631 goto cont;
4632 }
4633 DEBUG_VALID_MSG("Plus branch found");
4634 ret = 1;
4635 break;
4636 case XML_ELEMENT_CONTENT_MULT:
4637#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004638 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004639 DEBUG_VALID_MSG("Mult branch failed");
4640 } else {
4641 DEBUG_VALID_MSG("Mult branch found");
4642 }
4643#endif
4644 ret = 1;
4645 break;
4646 case XML_ELEMENT_CONTENT_OPT:
4647 DEBUG_VALID_MSG("Option branch failed");
4648 ret = 1;
4649 break;
4650 }
4651 } else {
4652 switch (CONT->ocur) {
4653 case XML_ELEMENT_CONTENT_OPT:
4654 DEBUG_VALID_MSG("Option branch succeeded");
4655 ret = 1;
4656 break;
4657 case XML_ELEMENT_CONTENT_ONCE:
4658 DEBUG_VALID_MSG("Once branch succeeded");
4659 ret = 1;
4660 break;
4661 case XML_ELEMENT_CONTENT_PLUS:
4662 if (STATE == ROLLBACK_PARENT) {
4663 DEBUG_VALID_MSG("Plus branch rollback");
4664 ret = 1;
4665 break;
4666 }
4667 if (NODE == NULL) {
4668 DEBUG_VALID_MSG("Plus branch exhausted");
4669 ret = 1;
4670 break;
4671 }
4672 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004673 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004674 goto cont;
4675 case XML_ELEMENT_CONTENT_MULT:
4676 if (STATE == ROLLBACK_PARENT) {
4677 DEBUG_VALID_MSG("Mult branch rollback");
4678 ret = 1;
4679 break;
4680 }
4681 if (NODE == NULL) {
4682 DEBUG_VALID_MSG("Mult branch exhausted");
4683 ret = 1;
4684 break;
4685 }
4686 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004687 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004688 goto cont;
4689 }
4690 }
4691 STATE = 0;
4692
4693 /*
4694 * Then act accordingly at the parent level
4695 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004696 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004697 if (CONT->parent == NULL)
4698 break;
4699
4700 switch (CONT->parent->type) {
4701 case XML_ELEMENT_CONTENT_PCDATA:
4702 DEBUG_VALID_MSG("Error: parent pcdata");
4703 return(-1);
4704 case XML_ELEMENT_CONTENT_ELEMENT:
4705 DEBUG_VALID_MSG("Error: parent element");
4706 return(-1);
4707 case XML_ELEMENT_CONTENT_OR:
4708 if (ret == 1) {
4709 DEBUG_VALID_MSG("Or succeeded");
4710 CONT = CONT->parent;
4711 DEPTH--;
4712 } else {
4713 DEBUG_VALID_MSG("Or failed");
4714 CONT = CONT->parent;
4715 DEPTH--;
4716 }
4717 break;
4718 case XML_ELEMENT_CONTENT_SEQ:
4719 if (ret == 0) {
4720 DEBUG_VALID_MSG("Sequence failed");
4721 CONT = CONT->parent;
4722 DEPTH--;
4723 } else if (CONT == CONT->parent->c1) {
4724 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4725 CONT = CONT->parent->c2;
4726 goto cont;
4727 } else {
4728 DEBUG_VALID_MSG("Sequence succeeded");
4729 CONT = CONT->parent;
4730 DEPTH--;
4731 }
4732 }
4733 }
4734 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004735 xmlNodePtr cur;
4736
4737 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004738 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4739 if (vstateVPop(ctxt) < 0 ) {
4740 DEBUG_VALID_MSG("exhaustion, failed");
4741 return(0);
4742 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004743 if (cur != ctxt->vstate->node)
4744 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004745 goto cont;
4746 }
4747 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004748 xmlNodePtr cur;
4749
4750 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004751 DEBUG_VALID_MSG("Failure, rollback");
4752 if (vstateVPop(ctxt) < 0 ) {
4753 DEBUG_VALID_MSG("exhaustion, failed");
4754 return(0);
4755 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004756 if (cur != ctxt->vstate->node)
4757 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004758 goto cont;
4759 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004760 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004761}
Daniel Veillard23e73572002-09-19 19:56:43 +00004762#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004763
4764/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00004765 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004766 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00004767 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004768 * @content: An element
4769 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4770 *
4771 * This will dump the list of elements to the buffer
4772 * Intended just for the debug routine
4773 */
4774static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00004775xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004776 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00004777 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004778
4779 if (node == NULL) return;
4780 if (glob) strcat(buf, "(");
4781 cur = node;
4782 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004783 len = strlen(buf);
4784 if (size - len < 50) {
4785 if ((size - len > 4) && (buf[len - 1] != '.'))
4786 strcat(buf, " ...");
4787 return;
4788 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004789 switch (cur->type) {
4790 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004791 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004792 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004793 if ((size - len > 4) && (buf[len - 1] != '.'))
4794 strcat(buf, " ...");
4795 return;
4796 }
4797 strcat(buf, (char *) cur->ns->prefix);
4798 strcat(buf, ":");
4799 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004800 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004801 if ((size - len > 4) && (buf[len - 1] != '.'))
4802 strcat(buf, " ...");
4803 return;
4804 }
4805 strcat(buf, (char *) cur->name);
4806 if (cur->next != NULL)
4807 strcat(buf, " ");
4808 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004809 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004810 if (xmlIsBlankNode(cur))
4811 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004812 case XML_CDATA_SECTION_NODE:
4813 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004814 strcat(buf, "CDATA");
4815 if (cur->next != NULL)
4816 strcat(buf, " ");
4817 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004818 case XML_ATTRIBUTE_NODE:
4819 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004820#ifdef LIBXML_DOCB_ENABLED
4821 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004822#endif
4823 case XML_HTML_DOCUMENT_NODE:
4824 case XML_DOCUMENT_TYPE_NODE:
4825 case XML_DOCUMENT_FRAG_NODE:
4826 case XML_NOTATION_NODE:
4827 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004828 strcat(buf, "???");
4829 if (cur->next != NULL)
4830 strcat(buf, " ");
4831 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004832 case XML_ENTITY_NODE:
4833 case XML_PI_NODE:
4834 case XML_DTD_NODE:
4835 case XML_COMMENT_NODE:
4836 case XML_ELEMENT_DECL:
4837 case XML_ATTRIBUTE_DECL:
4838 case XML_ENTITY_DECL:
4839 case XML_XINCLUDE_START:
4840 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004841 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004842 }
4843 cur = cur->next;
4844 }
4845 if (glob) strcat(buf, ")");
4846}
4847
4848/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004849 * xmlValidateElementContent:
4850 * @ctxt: the validation context
4851 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004852 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004853 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004854 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004855 *
4856 * Try to validate the content model of an element
4857 *
4858 * returns 1 if valid or 0 if not and -1 in case of error
4859 */
4860
4861static int
4862xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004863 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004864 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00004865#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00004866 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00004867#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00004868 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004869 xmlElementContentPtr cont;
4870 const xmlChar *name;
4871
4872 if (elemDecl == NULL)
4873 return(-1);
4874 cont = elemDecl->content;
4875 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004876
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004877#ifdef LIBXML_REGEXP_ENABLED
4878 /* Build the regexp associated to the content model */
4879 if (elemDecl->contModel == NULL)
4880 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4881 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004882 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004883 } else {
4884 xmlRegExecCtxtPtr exec;
4885
Daniel Veillardec498e12003-02-05 11:01:50 +00004886 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
4887 return(-1);
4888 }
Daniel Veillard01992e02002-10-09 10:20:30 +00004889 ctxt->nodeMax = 0;
4890 ctxt->nodeNr = 0;
4891 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004892 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4893 if (exec != NULL) {
4894 cur = child;
4895 while (cur != NULL) {
4896 switch (cur->type) {
4897 case XML_ENTITY_REF_NODE:
4898 /*
4899 * Push the current node to be able to roll back
4900 * and process within the entity
4901 */
4902 if ((cur->children != NULL) &&
4903 (cur->children->children != NULL)) {
4904 nodeVPush(ctxt, cur);
4905 cur = cur->children->children;
4906 continue;
4907 }
4908 break;
4909 case XML_TEXT_NODE:
4910 if (xmlIsBlankNode(cur))
4911 break;
4912 ret = 0;
4913 goto fail;
4914 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00004915 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004916 ret = 0;
4917 goto fail;
4918 case XML_ELEMENT_NODE:
4919 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004920 xmlChar fn[50];
4921 xmlChar *fullname;
4922
4923 fullname = xmlBuildQName(cur->name,
4924 cur->ns->prefix, fn, 50);
4925 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004926 ret = -1;
4927 goto fail;
4928 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004929 ret = xmlRegExecPushString(exec, fullname, NULL);
4930 if ((fullname != fn) && (fullname != cur->name))
4931 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004932 } else {
4933 ret = xmlRegExecPushString(exec, cur->name, NULL);
4934 }
4935 break;
4936 default:
4937 break;
4938 }
4939 /*
4940 * Switch to next element
4941 */
4942 cur = cur->next;
4943 while (cur == NULL) {
4944 cur = nodeVPop(ctxt);
4945 if (cur == NULL)
4946 break;
4947 cur = cur->next;
4948 }
4949 }
4950 ret = xmlRegExecPushString(exec, NULL, NULL);
4951fail:
4952 xmlRegFreeExecCtxt(exec);
4953 }
4954 }
4955#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004956 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004957 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004958 */
4959 ctxt->vstateMax = 8;
4960 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
4961 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
4962 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004963 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004964 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004965 }
4966 /*
4967 * The first entry in the stack is reserved to the current state
4968 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00004969 ctxt->nodeMax = 0;
4970 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00004971 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004972 ctxt->vstate = &ctxt->vstateTab[0];
4973 ctxt->vstateNr = 1;
4974 CONT = cont;
4975 NODE = child;
4976 DEPTH = 0;
4977 OCCURS = 0;
4978 STATE = 0;
4979 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004980 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004981 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
4982 "Content model for Element %s is ambiguous\n",
4983 name);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004984 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004985 /*
4986 * An entities reference appeared at this level.
4987 * Buid a minimal representation of this node content
4988 * sufficient to run the validation process on it
4989 */
4990 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004991 cur = child;
4992 while (cur != NULL) {
4993 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004994 case XML_ENTITY_REF_NODE:
4995 /*
4996 * Push the current node to be able to roll back
4997 * and process within the entity
4998 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004999 if ((cur->children != NULL) &&
5000 (cur->children->children != NULL)) {
5001 nodeVPush(ctxt, cur);
5002 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005003 continue;
5004 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005005 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005006 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005007 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005008 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005009 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005010 case XML_CDATA_SECTION_NODE:
5011 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005012 case XML_ELEMENT_NODE:
5013 /*
5014 * Allocate a new node and minimally fills in
5015 * what's required
5016 */
5017 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5018 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005019 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005020 xmlFreeNodeList(repl);
5021 ret = -1;
5022 goto done;
5023 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005024 tmp->type = cur->type;
5025 tmp->name = cur->name;
5026 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005027 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005028 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005029 if (repl == NULL)
5030 repl = last = tmp;
5031 else {
5032 last->next = tmp;
5033 last = tmp;
5034 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005035 if (cur->type == XML_CDATA_SECTION_NODE) {
5036 /*
5037 * E59 spaces in CDATA does not match the
5038 * nonterminal S
5039 */
5040 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5041 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005042 break;
5043 default:
5044 break;
5045 }
5046 /*
5047 * Switch to next element
5048 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005049 cur = cur->next;
5050 while (cur == NULL) {
5051 cur = nodeVPop(ctxt);
5052 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005053 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005054 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005055 }
5056 }
5057
5058 /*
5059 * Relaunch the validation
5060 */
5061 ctxt->vstate = &ctxt->vstateTab[0];
5062 ctxt->vstateNr = 1;
5063 CONT = cont;
5064 NODE = repl;
5065 DEPTH = 0;
5066 OCCURS = 0;
5067 STATE = 0;
5068 ret = xmlValidateElementType(ctxt);
5069 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005070#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005071 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005072 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5073 char expr[5000];
5074 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005075
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005076 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005077 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005078 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005079#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005080 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005081 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005082 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005083#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005084 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005085
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005086 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005087 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5088 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5089 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005090 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005091 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5092 "Element content does not follow the DTD, expecting %s, got %s\n",
5093 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005094 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005095 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005096 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005097 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005098 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005099 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005100 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005101 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5102 "Element content does not follow the DTD\n",
5103 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005104 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005105 }
5106 ret = 0;
5107 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005108 if (ret == -3)
5109 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005110
Daniel Veillard23e73572002-09-19 19:56:43 +00005111#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005112done:
5113 /*
5114 * Deallocate the copy if done, and free up the validation stack
5115 */
5116 while (repl != NULL) {
5117 tmp = repl->next;
5118 xmlFree(repl);
5119 repl = tmp;
5120 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005121 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005122 if (ctxt->vstateTab != NULL) {
5123 xmlFree(ctxt->vstateTab);
5124 ctxt->vstateTab = NULL;
5125 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005126#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005127 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005128 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005129 if (ctxt->nodeTab != NULL) {
5130 xmlFree(ctxt->nodeTab);
5131 ctxt->nodeTab = NULL;
5132 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005133 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005134
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005135}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005136
Owen Taylor3473f882001-02-23 17:55:21 +00005137/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005138 * xmlValidateCdataElement:
5139 * @ctxt: the validation context
5140 * @doc: a document instance
5141 * @elem: an element instance
5142 *
5143 * Check that an element follows #CDATA
5144 *
5145 * returns 1 if valid or 0 otherwise
5146 */
5147static int
5148xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5149 xmlNodePtr elem) {
5150 int ret = 1;
5151 xmlNodePtr cur, child;
5152
Daniel Veillardceb09b92002-10-04 11:46:37 +00005153 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005154 return(0);
5155
5156 child = elem->children;
5157
5158 cur = child;
5159 while (cur != NULL) {
5160 switch (cur->type) {
5161 case XML_ENTITY_REF_NODE:
5162 /*
5163 * Push the current node to be able to roll back
5164 * and process within the entity
5165 */
5166 if ((cur->children != NULL) &&
5167 (cur->children->children != NULL)) {
5168 nodeVPush(ctxt, cur);
5169 cur = cur->children->children;
5170 continue;
5171 }
5172 break;
5173 case XML_COMMENT_NODE:
5174 case XML_PI_NODE:
5175 case XML_TEXT_NODE:
5176 case XML_CDATA_SECTION_NODE:
5177 break;
5178 default:
5179 ret = 0;
5180 goto done;
5181 }
5182 /*
5183 * Switch to next element
5184 */
5185 cur = cur->next;
5186 while (cur == NULL) {
5187 cur = nodeVPop(ctxt);
5188 if (cur == NULL)
5189 break;
5190 cur = cur->next;
5191 }
5192 }
5193done:
5194 ctxt->nodeMax = 0;
5195 ctxt->nodeNr = 0;
5196 if (ctxt->nodeTab != NULL) {
5197 xmlFree(ctxt->nodeTab);
5198 ctxt->nodeTab = NULL;
5199 }
5200 return(ret);
5201}
5202
5203/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005204 * xmlValidateCheckMixed:
5205 * @ctxt: the validation context
5206 * @cont: the mixed content model
5207 * @qname: the qualified name as appearing in the serialization
5208 *
5209 * Check if the given node is part of the content model.
5210 *
5211 * Returns 1 if yes, 0 if no, -1 in case of error
5212 */
5213static int
5214xmlValidateCheckMixed(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
5215 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005216 const xmlChar *name;
5217 int plen;
5218 name = xmlSplitQName3(qname, &plen);
5219
5220 if (name == NULL) {
5221 while (cont != NULL) {
5222 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5223 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5224 return(1);
5225 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5226 (cont->c1 != NULL) &&
5227 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5228 if ((cont->c1->prefix == NULL) &&
5229 (xmlStrEqual(cont->c1->name, qname)))
5230 return(1);
5231 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5232 (cont->c1 == NULL) ||
5233 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005234 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5235 "Internal: MIXED struct corrupted\n",
5236 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005237 break;
5238 }
5239 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005240 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005241 } else {
5242 while (cont != NULL) {
5243 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5244 if ((cont->prefix != NULL) &&
5245 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5246 (xmlStrEqual(cont->name, name)))
5247 return(1);
5248 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5249 (cont->c1 != NULL) &&
5250 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5251 if ((cont->c1->prefix != NULL) &&
5252 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5253 (xmlStrEqual(cont->c1->name, name)))
5254 return(1);
5255 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5256 (cont->c1 == NULL) ||
5257 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005258 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5259 "Internal: MIXED struct corrupted\n",
5260 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005261 break;
5262 }
5263 cont = cont->c2;
5264 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005265 }
5266 return(0);
5267}
5268
5269/**
5270 * xmlValidGetElemDecl:
5271 * @ctxt: the validation context
5272 * @doc: a document instance
5273 * @elem: an element instance
5274 * @extsubset: pointer, (out) indicate if the declaration was found
5275 * in the external subset.
5276 *
5277 * Finds a declaration associated to an element in the document.
5278 *
5279 * returns the pointer to the declaration or NULL if not found.
5280 */
5281static xmlElementPtr
5282xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5283 xmlNodePtr elem, int *extsubset) {
5284 xmlElementPtr elemDecl = NULL;
5285 const xmlChar *prefix = NULL;
5286
5287 if ((elem == NULL) || (elem->name == NULL)) return(NULL);
5288 if (extsubset != NULL)
5289 *extsubset = 0;
5290
5291 /*
5292 * Fetch the declaration for the qualified name
5293 */
5294 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5295 prefix = elem->ns->prefix;
5296
5297 if (prefix != NULL) {
5298 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5299 elem->name, prefix);
5300 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5301 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5302 elem->name, prefix);
5303 if ((elemDecl != NULL) && (extsubset != NULL))
5304 *extsubset = 1;
5305 }
5306 }
5307
5308 /*
5309 * Fetch the declaration for the non qualified name
5310 * This is "non-strict" validation should be done on the
5311 * full QName but in that case being flexible makes sense.
5312 */
5313 if (elemDecl == NULL) {
5314 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5315 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5316 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5317 if ((elemDecl != NULL) && (extsubset != NULL))
5318 *extsubset = 1;
5319 }
5320 }
5321 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005322 xmlErrValidNode(ctxt, elem,
5323 XML_DTD_UNKNOWN_ELEM,
5324 "No declaration for element %s\n",
5325 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005326 }
5327 return(elemDecl);
5328}
5329
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005330#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005331/**
5332 * xmlValidatePushElement:
5333 * @ctxt: the validation context
5334 * @doc: a document instance
5335 * @elem: an element instance
5336 * @qname: the qualified name as appearing in the serialization
5337 *
5338 * Push a new element start on the validation stack.
5339 *
5340 * returns 1 if no validation problem was found or 0 otherwise
5341 */
5342int
5343xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5344 xmlNodePtr elem, const xmlChar *qname) {
5345 int ret = 1;
5346 xmlElementPtr eDecl;
5347 int extsubset = 0;
5348
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005349/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005350 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5351 xmlValidStatePtr state = ctxt->vstate;
5352 xmlElementPtr elemDecl;
5353
5354 /*
5355 * Check the new element agaisnt the content model of the new elem.
5356 */
5357 if (state->elemDecl != NULL) {
5358 elemDecl = state->elemDecl;
5359
5360 switch(elemDecl->etype) {
5361 case XML_ELEMENT_TYPE_UNDEFINED:
5362 ret = 0;
5363 break;
5364 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005365 xmlErrValidNode(ctxt, state->node,
5366 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005367 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005368 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005369 ret = 0;
5370 break;
5371 case XML_ELEMENT_TYPE_ANY:
5372 /* I don't think anything is required then */
5373 break;
5374 case XML_ELEMENT_TYPE_MIXED:
5375 /* simple case of declared as #PCDATA */
5376 if ((elemDecl->content != NULL) &&
5377 (elemDecl->content->type ==
5378 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005379 xmlErrValidNode(ctxt, state->node,
5380 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005381 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005382 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005383 ret = 0;
5384 } else {
5385 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5386 qname);
5387 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005388 xmlErrValidNode(ctxt, state->node,
5389 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005390 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005391 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005392 }
5393 }
5394 break;
5395 case XML_ELEMENT_TYPE_ELEMENT:
5396 /*
5397 * TODO:
5398 * VC: Standalone Document Declaration
5399 * - element types with element content, if white space
5400 * occurs directly within any instance of those types.
5401 */
5402 if (state->exec != NULL) {
5403 ret = xmlRegExecPushString(state->exec, qname, NULL);
5404 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005405 xmlErrValidNode(ctxt, state->node,
5406 XML_DTD_CONTENT_MODEL,
5407 "Element %s content does not follow the DTD, Misplaced %s\n",
5408 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005409 ret = 0;
5410 } else {
5411 ret = 1;
5412 }
5413 }
5414 break;
5415 }
5416 }
5417 }
5418 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5419 vstateVPush(ctxt, eDecl, elem);
5420 return(ret);
5421}
5422
5423/**
5424 * xmlValidatePushCData:
5425 * @ctxt: the validation context
5426 * @data: some character data read
5427 * @len: the lenght of the data
5428 *
5429 * check the CData parsed for validation in the current stack
5430 *
5431 * returns 1 if no validation problem was found or 0 otherwise
5432 */
5433int
5434xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5435 int ret = 1;
5436
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005437/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005438 if (len <= 0)
5439 return(ret);
5440 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5441 xmlValidStatePtr state = ctxt->vstate;
5442 xmlElementPtr elemDecl;
5443
5444 /*
5445 * Check the new element agaisnt the content model of the new elem.
5446 */
5447 if (state->elemDecl != NULL) {
5448 elemDecl = state->elemDecl;
5449
5450 switch(elemDecl->etype) {
5451 case XML_ELEMENT_TYPE_UNDEFINED:
5452 ret = 0;
5453 break;
5454 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005455 xmlErrValidNode(ctxt, state->node,
5456 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005457 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005458 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005459 ret = 0;
5460 break;
5461 case XML_ELEMENT_TYPE_ANY:
5462 break;
5463 case XML_ELEMENT_TYPE_MIXED:
5464 break;
5465 case XML_ELEMENT_TYPE_ELEMENT:
5466 if (len > 0) {
5467 int i;
5468
5469 for (i = 0;i < len;i++) {
5470 if (!IS_BLANK(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005471 xmlErrValidNode(ctxt, state->node,
5472 XML_DTD_CONTENT_MODEL,
5473 "Element %s content does not follow the DTD, Text not allowed\n",
5474 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005475 ret = 0;
5476 goto done;
5477 }
5478 }
5479 /*
5480 * TODO:
5481 * VC: Standalone Document Declaration
5482 * element types with element content, if white space
5483 * occurs directly within any instance of those types.
5484 */
5485 }
5486 break;
5487 }
5488 }
5489 }
5490done:
5491 return(ret);
5492}
5493
5494/**
5495 * xmlValidatePopElement:
5496 * @ctxt: the validation context
5497 * @doc: a document instance
5498 * @elem: an element instance
5499 * @qname: the qualified name as appearing in the serialization
5500 *
5501 * Pop the element end from the validation stack.
5502 *
5503 * returns 1 if no validation problem was found or 0 otherwise
5504 */
5505int
5506xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005507 xmlNodePtr elem ATTRIBUTE_UNUSED,
5508 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005509 int ret = 1;
5510
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005511/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005512 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5513 xmlValidStatePtr state = ctxt->vstate;
5514 xmlElementPtr elemDecl;
5515
5516 /*
5517 * Check the new element agaisnt the content model of the new elem.
5518 */
5519 if (state->elemDecl != NULL) {
5520 elemDecl = state->elemDecl;
5521
5522 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5523 if (state->exec != NULL) {
5524 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5525 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005526 xmlErrValidNode(ctxt, state->node,
5527 XML_DTD_CONTENT_MODEL,
5528 "Element %s content does not follow the DTD, Expecting more child\n",
5529 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005530 } else {
5531 /*
5532 * previous validation errors should not generate
5533 * a new one here
5534 */
5535 ret = 1;
5536 }
5537 }
5538 }
5539 }
5540 vstateVPop(ctxt);
5541 }
5542 return(ret);
5543}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005544#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005545
5546/**
Owen Taylor3473f882001-02-23 17:55:21 +00005547 * xmlValidateOneElement:
5548 * @ctxt: the validation context
5549 * @doc: a document instance
5550 * @elem: an element instance
5551 *
5552 * Try to validate a single element and it's attributes,
5553 * basically it does the following checks as described by the
5554 * XML-1.0 recommendation:
5555 * - [ VC: Element Valid ]
5556 * - [ VC: Required Attribute ]
5557 * Then call xmlValidateOneAttribute() for each attribute present.
5558 *
5559 * The ID/IDREF checkings are done separately
5560 *
5561 * returns 1 if valid or 0 otherwise
5562 */
5563
5564int
5565xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5566 xmlNodePtr elem) {
5567 xmlElementPtr elemDecl = NULL;
5568 xmlElementContentPtr cont;
5569 xmlAttributePtr attr;
5570 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005571 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005572 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005573 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005574
5575 CHECK_DTD;
5576
5577 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005578 switch (elem->type) {
5579 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005580 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5581 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005582 return(0);
5583 case XML_TEXT_NODE:
5584 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005585 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5586 "Text element has children !\n",
5587 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005588 return(0);
5589 }
5590 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005591 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5592 "Text element has attribute !\n",
5593 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005594 return(0);
5595 }
5596 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005597 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5598 "Text element has namespace !\n",
5599 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005600 return(0);
5601 }
5602 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005603 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5604 "Text element has namespace !\n",
5605 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005606 return(0);
5607 }
5608 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005609 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5610 "Text element has no content !\n",
5611 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005612 return(0);
5613 }
5614 return(1);
5615 case XML_XINCLUDE_START:
5616 case XML_XINCLUDE_END:
5617 return(1);
5618 case XML_CDATA_SECTION_NODE:
5619 case XML_ENTITY_REF_NODE:
5620 case XML_PI_NODE:
5621 case XML_COMMENT_NODE:
5622 return(1);
5623 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005624 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5625 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005626 return(0);
5627 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005628 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5629 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005630 return(0);
5631 case XML_DOCUMENT_NODE:
5632 case XML_DOCUMENT_TYPE_NODE:
5633 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005634 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5635 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005636 return(0);
5637 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005638 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5639 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005640 return(0);
5641 case XML_ELEMENT_NODE:
5642 break;
5643 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005644 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5645 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005646 return(0);
5647 }
Owen Taylor3473f882001-02-23 17:55:21 +00005648
5649 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005650 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005651 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005652 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5653 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005654 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005655
Daniel Veillardea7751d2002-12-20 00:16:24 +00005656 /*
5657 * If vstateNr is not zero that means continuous validation is
5658 * activated, do not try to check the content model at that level.
5659 */
5660 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005661 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005662 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005663 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005664 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5665 "No declaration for element %s\n",
5666 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005667 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005668 case XML_ELEMENT_TYPE_EMPTY:
5669 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005670 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005671 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005672 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005673 ret = 0;
5674 }
5675 break;
5676 case XML_ELEMENT_TYPE_ANY:
5677 /* I don't think anything is required then */
5678 break;
5679 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005680
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005681 /* simple case of declared as #PCDATA */
5682 if ((elemDecl->content != NULL) &&
5683 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5684 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5685 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005686 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005687 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005688 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005689 }
5690 break;
5691 }
Owen Taylor3473f882001-02-23 17:55:21 +00005692 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005693 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005694 while (child != NULL) {
5695 if (child->type == XML_ELEMENT_NODE) {
5696 name = child->name;
5697 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005698 xmlChar fn[50];
5699 xmlChar *fullname;
5700
5701 fullname = xmlBuildQName(child->name, child->ns->prefix,
5702 fn, 50);
5703 if (fullname == NULL)
5704 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005705 cont = elemDecl->content;
5706 while (cont != NULL) {
5707 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005708 if (xmlStrEqual(cont->name, fullname))
5709 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005710 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5711 (cont->c1 != NULL) &&
5712 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005713 if (xmlStrEqual(cont->c1->name, fullname))
5714 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005715 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5716 (cont->c1 == NULL) ||
5717 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005718 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5719 "Internal: MIXED struct corrupted\n",
5720 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005721 break;
5722 }
5723 cont = cont->c2;
5724 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005725 if ((fullname != fn) && (fullname != child->name))
5726 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005727 if (cont != NULL)
5728 goto child_ok;
5729 }
5730 cont = elemDecl->content;
5731 while (cont != NULL) {
5732 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5733 if (xmlStrEqual(cont->name, name)) break;
5734 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5735 (cont->c1 != NULL) &&
5736 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5737 if (xmlStrEqual(cont->c1->name, name)) break;
5738 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5739 (cont->c1 == NULL) ||
5740 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005741 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5742 "Internal: MIXED struct corrupted\n",
5743 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005744 break;
5745 }
5746 cont = cont->c2;
5747 }
5748 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005749 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00005750 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005751 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005752 ret = 0;
5753 }
5754 }
5755child_ok:
5756 child = child->next;
5757 }
5758 break;
5759 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005760 if ((doc->standalone == 1) && (extsubset == 1)) {
5761 /*
5762 * VC: Standalone Document Declaration
5763 * - element types with element content, if white space
5764 * occurs directly within any instance of those types.
5765 */
5766 child = elem->children;
5767 while (child != NULL) {
5768 if (child->type == XML_TEXT_NODE) {
5769 const xmlChar *content = child->content;
5770
5771 while (IS_BLANK(*content))
5772 content++;
5773 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005774 xmlErrValidNode(ctxt, elem,
5775 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005776"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005777 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005778 ret = 0;
5779 break;
5780 }
5781 }
5782 child =child->next;
5783 }
5784 }
Owen Taylor3473f882001-02-23 17:55:21 +00005785 child = elem->children;
5786 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005787 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005788 if (tmp <= 0)
5789 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005790 break;
5791 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005792 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00005793
5794 /* [ VC: Required Attribute ] */
5795 attr = elemDecl->attributes;
5796 while (attr != NULL) {
5797 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005798 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005799
Daniel Veillarde4301c82002-02-13 13:32:35 +00005800 if ((attr->prefix == NULL) &&
5801 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5802 xmlNsPtr ns;
5803
5804 ns = elem->nsDef;
5805 while (ns != NULL) {
5806 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005807 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005808 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00005809 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005810 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5811 xmlNsPtr ns;
5812
5813 ns = elem->nsDef;
5814 while (ns != NULL) {
5815 if (xmlStrEqual(attr->name, ns->prefix))
5816 goto found;
5817 ns = ns->next;
5818 }
5819 } else {
5820 xmlAttrPtr attrib;
5821
5822 attrib = elem->properties;
5823 while (attrib != NULL) {
5824 if (xmlStrEqual(attrib->name, attr->name)) {
5825 if (attr->prefix != NULL) {
5826 xmlNsPtr nameSpace = attrib->ns;
5827
5828 if (nameSpace == NULL)
5829 nameSpace = elem->ns;
5830 /*
5831 * qualified names handling is problematic, having a
5832 * different prefix should be possible but DTDs don't
5833 * allow to define the URI instead of the prefix :-(
5834 */
5835 if (nameSpace == NULL) {
5836 if (qualified < 0)
5837 qualified = 0;
5838 } else if (!xmlStrEqual(nameSpace->prefix,
5839 attr->prefix)) {
5840 if (qualified < 1)
5841 qualified = 1;
5842 } else
5843 goto found;
5844 } else {
5845 /*
5846 * We should allow applications to define namespaces
5847 * for their application even if the DTD doesn't
5848 * carry one, otherwise, basically we would always
5849 * break.
5850 */
5851 goto found;
5852 }
5853 }
5854 attrib = attrib->next;
5855 }
Owen Taylor3473f882001-02-23 17:55:21 +00005856 }
5857 if (qualified == -1) {
5858 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005859 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005860 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005861 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005862 ret = 0;
5863 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005864 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005865 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005866 elem->name, attr->prefix,attr->name);
5867 ret = 0;
5868 }
5869 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005870 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005871 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005872 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005873 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005874 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005875 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005876 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005877 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005878 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5879 /*
5880 * Special tests checking #FIXED namespace declarations
5881 * have the right value since this is not done as an
5882 * attribute checking
5883 */
5884 if ((attr->prefix == NULL) &&
5885 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5886 xmlNsPtr ns;
5887
5888 ns = elem->nsDef;
5889 while (ns != NULL) {
5890 if (ns->prefix == NULL) {
5891 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005892 xmlErrValidNode(ctxt, elem,
5893 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00005894 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005895 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005896 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005897 }
5898 goto found;
5899 }
5900 ns = ns->next;
5901 }
5902 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5903 xmlNsPtr ns;
5904
5905 ns = elem->nsDef;
5906 while (ns != NULL) {
5907 if (xmlStrEqual(attr->name, ns->prefix)) {
5908 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005909 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005910 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005911 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005912 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005913 }
5914 goto found;
5915 }
5916 ns = ns->next;
5917 }
5918 }
Owen Taylor3473f882001-02-23 17:55:21 +00005919 }
5920found:
5921 attr = attr->nexth;
5922 }
5923 return(ret);
5924}
5925
5926/**
5927 * xmlValidateRoot:
5928 * @ctxt: the validation context
5929 * @doc: a document instance
5930 *
5931 * Try to validate a the root element
5932 * basically it does the following check as described by the
5933 * XML-1.0 recommendation:
5934 * - [ VC: Root Element Type ]
5935 * it doesn't try to recurse or apply other check to the element
5936 *
5937 * returns 1 if valid or 0 otherwise
5938 */
5939
5940int
5941xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
5942 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00005943 int ret;
5944
Owen Taylor3473f882001-02-23 17:55:21 +00005945 if (doc == NULL) return(0);
5946
5947 root = xmlDocGetRootElement(doc);
5948 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005949 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
5950 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005951 return(0);
5952 }
5953
5954 /*
5955 * When doing post validation against a separate DTD, those may
5956 * no internal subset has been generated
5957 */
5958 if ((doc->intSubset != NULL) &&
5959 (doc->intSubset->name != NULL)) {
5960 /*
5961 * Check first the document root against the NQName
5962 */
5963 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
5964 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005965 xmlChar fn[50];
5966 xmlChar *fullname;
5967
5968 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
5969 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005970 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00005971 return(0);
5972 }
5973 ret = xmlStrEqual(doc->intSubset->name, fullname);
5974 if ((fullname != fn) && (fullname != root->name))
5975 xmlFree(fullname);
5976 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00005977 goto name_ok;
5978 }
5979 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
5980 (xmlStrEqual(root->name, BAD_CAST "html")))
5981 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005982 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
5983 "root and DTD name do not match '%s' and '%s'\n",
5984 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005985 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005986 }
5987 }
5988name_ok:
5989 return(1);
5990}
5991
5992
5993/**
5994 * xmlValidateElement:
5995 * @ctxt: the validation context
5996 * @doc: a document instance
5997 * @elem: an element instance
5998 *
5999 * Try to validate the subtree under an element
6000 *
6001 * returns 1 if valid or 0 otherwise
6002 */
6003
6004int
6005xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6006 xmlNodePtr child;
6007 xmlAttrPtr attr;
6008 xmlChar *value;
6009 int ret = 1;
6010
6011 if (elem == NULL) return(0);
6012
6013 /*
6014 * XInclude elements were added after parsing in the infoset,
6015 * they don't really mean anything validation wise.
6016 */
6017 if ((elem->type == XML_XINCLUDE_START) ||
6018 (elem->type == XML_XINCLUDE_END))
6019 return(1);
6020
6021 CHECK_DTD;
6022
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006023 /*
6024 * Entities references have to be handled separately
6025 */
6026 if (elem->type == XML_ENTITY_REF_NODE) {
6027 return(1);
6028 }
6029
Owen Taylor3473f882001-02-23 17:55:21 +00006030 ret &= xmlValidateOneElement(ctxt, doc, elem);
6031 attr = elem->properties;
6032 while(attr != NULL) {
6033 value = xmlNodeListGetString(doc, attr->children, 0);
6034 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6035 if (value != NULL)
6036 xmlFree(value);
6037 attr= attr->next;
6038 }
6039 child = elem->children;
6040 while (child != NULL) {
6041 ret &= xmlValidateElement(ctxt, doc, child);
6042 child = child->next;
6043 }
6044
6045 return(ret);
6046}
6047
Daniel Veillard8730c562001-02-26 10:49:57 +00006048/**
6049 * xmlValidateRef:
6050 * @ref: A reference to be validated
6051 * @ctxt: Validation context
6052 * @name: Name of ID we are searching for
6053 *
6054 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006055static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006056xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006057 const xmlChar *name) {
6058 xmlAttrPtr id;
6059 xmlAttrPtr attr;
6060
6061 if (ref == NULL)
6062 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006063 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006064 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006065 attr = ref->attr;
6066 if (attr == NULL) {
6067 xmlChar *dup, *str = NULL, *cur, save;
6068
6069 dup = xmlStrdup(name);
6070 if (dup == NULL) {
6071 ctxt->valid = 0;
6072 return;
6073 }
6074 cur = dup;
6075 while (*cur != 0) {
6076 str = cur;
6077 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6078 save = *cur;
6079 *cur = 0;
6080 id = xmlGetID(ctxt->doc, str);
6081 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006082 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006083 "attribute %s line %d references an unknown ID \"%s\"\n",
6084 ref->name, ref->lineno, str);
6085 ctxt->valid = 0;
6086 }
6087 if (save == 0)
6088 break;
6089 *cur = save;
6090 while (IS_BLANK(*cur)) cur++;
6091 }
6092 xmlFree(dup);
6093 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006094 id = xmlGetID(ctxt->doc, name);
6095 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006096 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006097 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006098 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006099 ctxt->valid = 0;
6100 }
6101 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6102 xmlChar *dup, *str = NULL, *cur, save;
6103
6104 dup = xmlStrdup(name);
6105 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006106 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006107 ctxt->valid = 0;
6108 return;
6109 }
6110 cur = dup;
6111 while (*cur != 0) {
6112 str = cur;
6113 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6114 save = *cur;
6115 *cur = 0;
6116 id = xmlGetID(ctxt->doc, str);
6117 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006118 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006119 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006120 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006121 ctxt->valid = 0;
6122 }
6123 if (save == 0)
6124 break;
6125 *cur = save;
6126 while (IS_BLANK(*cur)) cur++;
6127 }
6128 xmlFree(dup);
6129 }
6130}
6131
6132/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006133 * xmlWalkValidateList:
6134 * @data: Contents of current link
6135 * @user: Value supplied by the user
6136 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006137 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006138 */
6139static int
6140xmlWalkValidateList(const void *data, const void *user)
6141{
6142 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6143 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6144 return 1;
6145}
6146
6147/**
6148 * xmlValidateCheckRefCallback:
6149 * @ref_list: List of references
6150 * @ctxt: Validation context
6151 * @name: Name of ID we are searching for
6152 *
6153 */
6154static void
6155xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6156 const xmlChar *name) {
6157 xmlValidateMemo memo;
6158
6159 if (ref_list == NULL)
6160 return;
6161 memo.ctxt = ctxt;
6162 memo.name = name;
6163
6164 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6165
6166}
6167
6168/**
Owen Taylor3473f882001-02-23 17:55:21 +00006169 * xmlValidateDocumentFinal:
6170 * @ctxt: the validation context
6171 * @doc: a document instance
6172 *
6173 * Does the final step for the document validation once all the
6174 * incremental validation steps have been completed
6175 *
6176 * basically it does the following checks described by the XML Rec
6177 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006178 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006179 *
6180 * returns 1 if valid or 0 otherwise
6181 */
6182
6183int
6184xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6185 xmlRefTablePtr table;
6186
6187 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006188 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6189 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006190 return(0);
6191 }
6192
6193 /*
6194 * Check all the NOTATION/NOTATIONS attributes
6195 */
6196 /*
6197 * Check all the ENTITY/ENTITIES attributes definition for validity
6198 */
6199 /*
6200 * Check all the IDREF/IDREFS attributes definition for validity
6201 */
6202 table = (xmlRefTablePtr) doc->refs;
6203 ctxt->doc = doc;
6204 ctxt->valid = 1;
6205 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6206 return(ctxt->valid);
6207}
6208
6209/**
6210 * xmlValidateDtd:
6211 * @ctxt: the validation context
6212 * @doc: a document instance
6213 * @dtd: a dtd instance
6214 *
6215 * Try to validate the document against the dtd instance
6216 *
6217 * basically it does check all the definitions in the DtD.
6218 *
6219 * returns 1 if valid or 0 otherwise
6220 */
6221
6222int
6223xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6224 int ret;
6225 xmlDtdPtr oldExt;
6226 xmlNodePtr root;
6227
6228 if (dtd == NULL) return(0);
6229 if (doc == NULL) return(0);
6230 oldExt = doc->extSubset;
6231 doc->extSubset = dtd;
6232 ret = xmlValidateRoot(ctxt, doc);
6233 if (ret == 0) {
6234 doc->extSubset = oldExt;
6235 return(ret);
6236 }
6237 if (doc->ids != NULL) {
6238 xmlFreeIDTable(doc->ids);
6239 doc->ids = NULL;
6240 }
6241 if (doc->refs != NULL) {
6242 xmlFreeRefTable(doc->refs);
6243 doc->refs = NULL;
6244 }
6245 root = xmlDocGetRootElement(doc);
6246 ret = xmlValidateElement(ctxt, doc, root);
6247 ret &= xmlValidateDocumentFinal(ctxt, doc);
6248 doc->extSubset = oldExt;
6249 return(ret);
6250}
6251
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006252static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006253xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6254 const xmlChar *name ATTRIBUTE_UNUSED) {
6255 if (cur == NULL)
6256 return;
6257 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6258 xmlChar *notation = cur->content;
6259
Daniel Veillard878eab02002-02-19 13:46:09 +00006260 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006261 int ret;
6262
6263 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6264 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006265 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006266 }
6267 }
6268 }
6269}
6270
6271static void
Owen Taylor3473f882001-02-23 17:55:21 +00006272xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006273 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006274 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006275 xmlDocPtr doc;
6276 xmlElementPtr elem;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006277
Owen Taylor3473f882001-02-23 17:55:21 +00006278 if (cur == NULL)
6279 return;
6280 switch (cur->atype) {
6281 case XML_ATTRIBUTE_CDATA:
6282 case XML_ATTRIBUTE_ID:
6283 case XML_ATTRIBUTE_IDREF :
6284 case XML_ATTRIBUTE_IDREFS:
6285 case XML_ATTRIBUTE_NMTOKEN:
6286 case XML_ATTRIBUTE_NMTOKENS:
6287 case XML_ATTRIBUTE_ENUMERATION:
6288 break;
6289 case XML_ATTRIBUTE_ENTITY:
6290 case XML_ATTRIBUTE_ENTITIES:
6291 case XML_ATTRIBUTE_NOTATION:
6292 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006293
6294 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6295 cur->atype, cur->defaultValue);
6296 if ((ret == 0) && (ctxt->valid == 1))
6297 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006298 }
6299 if (cur->tree != NULL) {
6300 xmlEnumerationPtr tree = cur->tree;
6301 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006302 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006303 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006304 if ((ret == 0) && (ctxt->valid == 1))
6305 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006306 tree = tree->next;
6307 }
6308 }
6309 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006310 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6311 doc = cur->doc;
6312 if ((doc == NULL) || (cur->elem == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006313 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006314 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006315 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006316 return;
6317 }
6318 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6319 if (elem == NULL)
6320 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
6321 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006322 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006323 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006324 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006325 return;
6326 }
6327 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006328 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006329 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006330 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006331 ctxt->valid = 0;
6332 }
6333 }
Owen Taylor3473f882001-02-23 17:55:21 +00006334}
6335
6336/**
6337 * xmlValidateDtdFinal:
6338 * @ctxt: the validation context
6339 * @doc: a document instance
6340 *
6341 * Does the final step for the dtds validation once all the
6342 * subsets have been parsed
6343 *
6344 * basically it does the following checks described by the XML Rec
6345 * - check that ENTITY and ENTITIES type attributes default or
6346 * possible values matches one of the defined entities.
6347 * - check that NOTATION type attributes default or
6348 * possible values matches one of the defined notations.
6349 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006350 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006351 */
6352
6353int
6354xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006355 xmlDtdPtr dtd;
6356 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006357 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006358
6359 if (doc == NULL) return(0);
6360 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6361 return(0);
6362 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006363 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006364 dtd = doc->intSubset;
6365 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6366 table = (xmlAttributeTablePtr) dtd->attributes;
6367 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006368 }
6369 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006370 entities = (xmlEntitiesTablePtr) dtd->entities;
6371 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6372 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006373 }
6374 dtd = doc->extSubset;
6375 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6376 table = (xmlAttributeTablePtr) dtd->attributes;
6377 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006378 }
6379 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006380 entities = (xmlEntitiesTablePtr) dtd->entities;
6381 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6382 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006383 }
6384 return(ctxt->valid);
6385}
6386
6387/**
6388 * xmlValidateDocument:
6389 * @ctxt: the validation context
6390 * @doc: a document instance
6391 *
6392 * Try to validate the document instance
6393 *
6394 * basically it does the all the checks described by the XML Rec
6395 * i.e. validates the internal and external subset (if present)
6396 * and validate the document tree.
6397 *
6398 * returns 1 if valid or 0 otherwise
6399 */
6400
6401int
6402xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6403 int ret;
6404 xmlNodePtr root;
6405
Daniel Veillard2fd85422002-10-16 14:32:41 +00006406 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006407 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6408 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006409 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006410 }
Owen Taylor3473f882001-02-23 17:55:21 +00006411 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6412 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6413 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6414 doc->intSubset->SystemID);
6415 if (doc->extSubset == NULL) {
6416 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006417 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006418 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006419 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006420 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006421 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006422 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006423 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006424 }
6425 return(0);
6426 }
6427 }
6428
6429 if (doc->ids != NULL) {
6430 xmlFreeIDTable(doc->ids);
6431 doc->ids = NULL;
6432 }
6433 if (doc->refs != NULL) {
6434 xmlFreeRefTable(doc->refs);
6435 doc->refs = NULL;
6436 }
6437 ret = xmlValidateDtdFinal(ctxt, doc);
6438 if (!xmlValidateRoot(ctxt, doc)) return(0);
6439
6440 root = xmlDocGetRootElement(doc);
6441 ret &= xmlValidateElement(ctxt, doc, root);
6442 ret &= xmlValidateDocumentFinal(ctxt, doc);
6443 return(ret);
6444}
6445
Owen Taylor3473f882001-02-23 17:55:21 +00006446/************************************************************************
6447 * *
6448 * Routines for dynamic validation editing *
6449 * *
6450 ************************************************************************/
6451
6452/**
6453 * xmlValidGetPotentialChildren:
6454 * @ctree: an element content tree
6455 * @list: an array to store the list of child names
6456 * @len: a pointer to the number of element in the list
6457 * @max: the size of the array
6458 *
6459 * Build/extend a list of potential children allowed by the content tree
6460 *
6461 * returns the number of element in the list, or -1 in case of error.
6462 */
6463
6464int
6465xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6466 int *len, int max) {
6467 int i;
6468
6469 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6470 return(-1);
6471 if (*len >= max) return(*len);
6472
6473 switch (ctree->type) {
6474 case XML_ELEMENT_CONTENT_PCDATA:
6475 for (i = 0; i < *len;i++)
6476 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6477 list[(*len)++] = BAD_CAST "#PCDATA";
6478 break;
6479 case XML_ELEMENT_CONTENT_ELEMENT:
6480 for (i = 0; i < *len;i++)
6481 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6482 list[(*len)++] = ctree->name;
6483 break;
6484 case XML_ELEMENT_CONTENT_SEQ:
6485 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6486 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6487 break;
6488 case XML_ELEMENT_CONTENT_OR:
6489 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6490 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6491 break;
6492 }
6493
6494 return(*len);
6495}
6496
6497/**
6498 * xmlValidGetValidElements:
6499 * @prev: an element to insert after
6500 * @next: an element to insert next
6501 * @list: an array to store the list of child names
6502 * @max: the size of the array
6503 *
6504 * This function returns the list of authorized children to insert
6505 * within an existing tree while respecting the validity constraints
6506 * forced by the Dtd. The insertion point is defined using @prev and
6507 * @next in the following ways:
6508 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6509 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6510 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6511 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6512 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6513 *
6514 * pointers to the element names are inserted at the beginning of the array
6515 * and do not need to be freed.
6516 *
6517 * returns the number of element in the list, or -1 in case of error. If
6518 * the function returns the value @max the caller is invited to grow the
6519 * receiving array and retry.
6520 */
6521
6522int
6523xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
6524 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006525 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006526 int nb_valid_elements = 0;
6527 const xmlChar *elements[256];
6528 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006529 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006530
6531 xmlNode *ref_node;
6532 xmlNode *parent;
6533 xmlNode *test_node;
6534
6535 xmlNode *prev_next;
6536 xmlNode *next_prev;
6537 xmlNode *parent_childs;
6538 xmlNode *parent_last;
6539
6540 xmlElement *element_desc;
6541
Daniel Veillardbb4e46d2002-03-10 16:49:08 +00006542 memset(&vctxt, 0, sizeof (xmlValidCtxt));
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006543
Owen Taylor3473f882001-02-23 17:55:21 +00006544 if (prev == NULL && next == NULL)
6545 return(-1);
6546
6547 if (list == NULL) return(-1);
6548 if (max <= 0) return(-1);
6549
6550 nb_valid_elements = 0;
6551 ref_node = prev ? prev : next;
6552 parent = ref_node->parent;
6553
6554 /*
6555 * Retrieves the parent element declaration
6556 */
6557 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6558 parent->name);
6559 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6560 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6561 parent->name);
6562 if (element_desc == NULL) return(-1);
6563
6564 /*
6565 * Do a backup of the current tree structure
6566 */
6567 prev_next = prev ? prev->next : NULL;
6568 next_prev = next ? next->prev : NULL;
6569 parent_childs = parent->children;
6570 parent_last = parent->last;
6571
6572 /*
6573 * Creates a dummy node and insert it into the tree
6574 */
6575 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
6576 test_node->doc = ref_node->doc;
6577 test_node->parent = parent;
6578 test_node->prev = prev;
6579 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006580 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006581
6582 if (prev) prev->next = test_node;
6583 else parent->children = test_node;
6584
6585 if (next) next->prev = test_node;
6586 else parent->last = test_node;
6587
6588 /*
6589 * Insert each potential child node and check if the parent is
6590 * still valid
6591 */
6592 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6593 elements, &nb_elements, 256);
6594
6595 for (i = 0;i < nb_elements;i++) {
6596 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006597 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006598 int j;
6599
6600 for (j = 0; j < nb_valid_elements;j++)
6601 if (xmlStrEqual(elements[i], list[j])) break;
6602 list[nb_valid_elements++] = elements[i];
6603 if (nb_valid_elements >= max) break;
6604 }
6605 }
6606
6607 /*
6608 * Restore the tree structure
6609 */
6610 if (prev) prev->next = prev_next;
6611 if (next) next->prev = next_prev;
6612 parent->children = parent_childs;
6613 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006614
6615 /*
6616 * Free up the dummy node
6617 */
6618 test_node->name = name;
6619 xmlFreeNode(test_node);
6620
Owen Taylor3473f882001-02-23 17:55:21 +00006621 return(nb_valid_elements);
6622}
Daniel Veillard4432df22003-09-28 18:58:27 +00006623#endif /* LIBXML_VALID_ENABLED */
6624