blob: 5630c6c0c213c53a80cf76ad013ff0170fdbe9d4 [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 Veillardbb5abab2003-10-03 22:21:51 +000056 xmlGenericErrorFunc channel = NULL;
57 xmlParserCtxtPtr pctxt = NULL;
58 void *data = NULL;
59
60 if (ctxt != NULL) {
61 channel = ctxt->error;
62 data = ctxt->userData;
63 pctxt = ctxt->userData;
64 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000065 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000066 __xmlRaiseError(NULL, channel, data,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000067 pctxt, NULL, XML_FROM_DTD, XML_ERR_NO_MEMORY,
68 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
69 "Memory allocation failed : %s\n", extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000070 else
Daniel Veillard73000572003-10-11 11:26:42 +000071 __xmlRaiseError(NULL, channel, data,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000072 pctxt, NULL, XML_FROM_DTD, XML_ERR_NO_MEMORY,
73 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
74 "Memory allocation failed\n");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000075}
76
77/**
78 * xmlErrValid:
79 * @ctxt: an XML validation parser context
Daniel Veillardbb5abab2003-10-03 22:21:51 +000080 * @error: the error number
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000081 * @extra: extra informations
82 *
83 * Handle a validation error
84 */
85static void
86xmlErrValid(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlParserErrors error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000087 const char *msg, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000088{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000089 xmlGenericErrorFunc channel = NULL;
90 xmlParserCtxtPtr pctxt = NULL;
91 void *data = NULL;
92
93 if (ctxt != NULL) {
94 channel = ctxt->error;
95 data = ctxt->userData;
96 pctxt = ctxt->userData;
97 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000098 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000099 __xmlRaiseError(NULL, channel, data,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000100 pctxt, NULL, XML_FROM_DTD, error,
101 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
102 msg, extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000103 else
Daniel Veillard73000572003-10-11 11:26:42 +0000104 __xmlRaiseError(NULL, channel, data,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000105 pctxt, NULL, XML_FROM_DTD, error,
106 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
107 msg);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000108}
109
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000110/**
111 * xmlErrValidNodeNr:
112 * @ctxt: an XML validation parser context
113 * @node: the node raising the error
114 * @error: the error number
115 * @str1: extra informations
116 * @int2: extra informations
117 * @str3: extra informations
118 *
119 * Handle a validation error, provide contextual informations
120 */
121static void
122xmlErrValidNodeNr(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
123 xmlNodePtr node, xmlParserErrors error,
124 const char *msg, const xmlChar * str1,
125 int int2, const xmlChar * str3)
126{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000127 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000128 xmlGenericErrorFunc channel = NULL;
129 xmlParserCtxtPtr pctxt = NULL;
130 void *data = NULL;
131
132 if (ctxt != NULL) {
133 channel = ctxt->error;
134 data = ctxt->userData;
135 pctxt = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000136 pctxt = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000137 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000138 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_DTD, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000139 XML_ERR_ERROR, NULL, 0,
140 (const char *) str1,
141 (const char *) str3,
142 NULL, int2, 0, msg, str1, int2, str3);
143}
144/**
145 * xmlErrValidNode:
146 * @ctxt: an XML validation parser context
147 * @node: the node raising the error
148 * @error: the error number
149 * @str1: extra informations
150 * @str2: extra informations
151 * @str3: extra informations
152 *
153 * Handle a validation error, provide contextual informations
154 */
155static void
156xmlErrValidNode(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
157 xmlNodePtr node, xmlParserErrors error,
158 const char *msg, const xmlChar * str1,
159 const xmlChar * str2, const xmlChar * str3)
160{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000161 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000162 xmlGenericErrorFunc channel = NULL;
163 xmlParserCtxtPtr pctxt = NULL;
164 void *data = NULL;
165
166 if (ctxt != NULL) {
167 channel = ctxt->error;
168 data = ctxt->userData;
169 pctxt = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000170 pctxt = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000171 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000172 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_DTD, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000173 XML_ERR_ERROR, NULL, 0,
174 (const char *) str1,
175 (const char *) str1,
176 (const char *) str3, 0, 0, msg, str1, str2, str3);
177}
178/**
179 * xmlErrValidWarning:
180 * @ctxt: an XML validation parser context
181 * @node: the node raising the error
182 * @error: the error number
183 * @str1: extra informations
184 * @str2: extra informations
185 * @str3: extra informations
186 *
187 * Handle a validation error, provide contextual informations
188 */
189static void
190xmlErrValidWarning(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
191 xmlNodePtr node, xmlParserErrors error,
192 const char *msg, const xmlChar * str1,
193 const xmlChar * str2, const xmlChar * str3)
194{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000195 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000196 xmlGenericErrorFunc channel = NULL;
197 xmlParserCtxtPtr pctxt = NULL;
198 void *data = NULL;
199
200 if (ctxt != NULL) {
201 channel = ctxt->error;
202 data = ctxt->userData;
203 pctxt = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000204 pctxt = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000205 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000206 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_DTD, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000207 XML_ERR_WARNING, NULL, 0,
208 (const char *) str1,
209 (const char *) str1,
210 (const char *) str3, 0, 0, msg, str1, str2, str3);
211}
212
213
Daniel Veillardea7751d2002-12-20 00:16:24 +0000214
215#ifdef LIBXML_REGEXP_ENABLED
216/*
217 * If regexp are enabled we can do continuous validation without the
218 * need of a tree to validate the content model. this is done in each
219 * callbacks.
220 * Each xmlValidState represent the validation state associated to the
221 * set of nodes currently open from the document root to the current element.
222 */
223
224
225typedef struct _xmlValidState {
226 xmlElementPtr elemDecl; /* pointer to the content model */
227 xmlNodePtr node; /* pointer to the current node */
228 xmlRegExecCtxtPtr exec; /* regexp runtime */
229} _xmlValidState;
230
231
232static int
233vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000234 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000235 ctxt->vstateMax = 10;
236 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
237 sizeof(ctxt->vstateTab[0]));
238 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000239 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000240 return(-1);
241 }
242 }
243
244 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000245 xmlValidState *tmp;
246
247 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
248 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
249 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000250 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000251 return(-1);
252 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000253 ctxt->vstateMax *= 2;
254 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000255 }
256 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
257 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
258 ctxt->vstateTab[ctxt->vstateNr].node = node;
259 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
260 if (elemDecl->contModel == NULL)
261 xmlValidBuildContentModel(ctxt, elemDecl);
262 if (elemDecl->contModel != NULL) {
263 ctxt->vstateTab[ctxt->vstateNr].exec =
264 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
265 } else {
266 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000267 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
268 XML_ERR_INTERNAL_ERROR,
269 "Failed to build content model regexp for %s\n",
270 node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000271 }
272 }
273 return(ctxt->vstateNr++);
274}
275
276static int
277vstateVPop(xmlValidCtxtPtr ctxt) {
278 xmlElementPtr elemDecl;
279
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000280 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000281 ctxt->vstateNr--;
282 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
283 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
284 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
285 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
286 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
287 }
288 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
289 if (ctxt->vstateNr >= 1)
290 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
291 else
292 ctxt->vstate = NULL;
293 return(ctxt->vstateNr);
294}
295
296#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000297/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000298 * If regexp are not enabled, it uses a home made algorithm less
299 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000300 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000301 * only restriction is on the deepness of the tree limited by the
302 * size of the occurs bitfield
303 *
304 * this is the content of a saved state for rollbacks
305 */
306
307#define ROLLBACK_OR 0
308#define ROLLBACK_PARENT 1
309
Daniel Veillardb44025c2001-10-11 22:55:55 +0000310typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000311 xmlElementContentPtr cont; /* pointer to the content model subtree */
312 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000313 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000314 unsigned char depth; /* current depth in the overall tree */
315 unsigned char state; /* ROLLBACK_XXX */
316} _xmlValidState;
317
Daniel Veillardfc57b412002-04-29 15:50:14 +0000318#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000319#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
320#define CONT ctxt->vstate->cont
321#define NODE ctxt->vstate->node
322#define DEPTH ctxt->vstate->depth
323#define OCCURS ctxt->vstate->occurs
324#define STATE ctxt->vstate->state
325
Daniel Veillard5344c602001-12-31 16:37:34 +0000326#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
327#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000328
Daniel Veillard5344c602001-12-31 16:37:34 +0000329#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
330#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000331
332static int
333vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
334 xmlNodePtr node, unsigned char depth, long occurs,
335 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000336 int i = ctxt->vstateNr - 1;
337
Daniel Veillard940492d2002-04-15 10:15:25 +0000338 if (ctxt->vstateNr > MAX_RECURSE) {
339 return(-1);
340 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000341 if (ctxt->vstateTab == NULL) {
342 ctxt->vstateMax = 8;
343 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
344 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
345 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000346 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000347 return(-1);
348 }
349 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000350 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000351 xmlValidState *tmp;
352
353 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
354 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
355 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000356 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000357 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000358 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000359 ctxt->vstateMax *= 2;
360 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000361 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000362 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000363 /*
364 * Don't push on the stack a state already here
365 */
366 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
367 (ctxt->vstateTab[i].node == node) &&
368 (ctxt->vstateTab[i].depth == depth) &&
369 (ctxt->vstateTab[i].occurs == occurs) &&
370 (ctxt->vstateTab[i].state == state))
371 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000372 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
373 ctxt->vstateTab[ctxt->vstateNr].node = node;
374 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
375 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
376 ctxt->vstateTab[ctxt->vstateNr].state = state;
377 return(ctxt->vstateNr++);
378}
379
380static int
381vstateVPop(xmlValidCtxtPtr ctxt) {
382 if (ctxt->vstateNr <= 1) return(-1);
383 ctxt->vstateNr--;
384 ctxt->vstate = &ctxt->vstateTab[0];
385 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
386 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
387 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
388 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
389 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
390 return(ctxt->vstateNr);
391}
392
Daniel Veillard118aed72002-09-24 14:13:13 +0000393#endif /* LIBXML_REGEXP_ENABLED */
394
Daniel Veillard1c732d22002-11-30 11:22:59 +0000395static int
396nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
397{
398 if (ctxt->nodeMax <= 0) {
399 ctxt->nodeMax = 4;
400 ctxt->nodeTab =
401 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
402 sizeof(ctxt->nodeTab[0]));
403 if (ctxt->nodeTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000404 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000405 ctxt->nodeMax = 0;
406 return (0);
407 }
408 }
409 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000410 xmlNodePtr *tmp;
411 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
412 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
413 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000414 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000415 return (0);
416 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000417 ctxt->nodeMax *= 2;
418 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000419 }
420 ctxt->nodeTab[ctxt->nodeNr] = value;
421 ctxt->node = value;
422 return (ctxt->nodeNr++);
423}
424static xmlNodePtr
425nodeVPop(xmlValidCtxtPtr ctxt)
426{
427 xmlNodePtr ret;
428
429 if (ctxt->nodeNr <= 0)
430 return (0);
431 ctxt->nodeNr--;
432 if (ctxt->nodeNr > 0)
433 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
434 else
435 ctxt->node = NULL;
436 ret = ctxt->nodeTab[ctxt->nodeNr];
437 ctxt->nodeTab[ctxt->nodeNr] = 0;
438 return (ret);
439}
Owen Taylor3473f882001-02-23 17:55:21 +0000440
Owen Taylor3473f882001-02-23 17:55:21 +0000441#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000442static void
443xmlValidPrintNode(xmlNodePtr cur) {
444 if (cur == NULL) {
445 xmlGenericError(xmlGenericErrorContext, "null");
446 return;
447 }
448 switch (cur->type) {
449 case XML_ELEMENT_NODE:
450 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
451 break;
452 case XML_TEXT_NODE:
453 xmlGenericError(xmlGenericErrorContext, "text ");
454 break;
455 case XML_CDATA_SECTION_NODE:
456 xmlGenericError(xmlGenericErrorContext, "cdata ");
457 break;
458 case XML_ENTITY_REF_NODE:
459 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
460 break;
461 case XML_PI_NODE:
462 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
463 break;
464 case XML_COMMENT_NODE:
465 xmlGenericError(xmlGenericErrorContext, "comment ");
466 break;
467 case XML_ATTRIBUTE_NODE:
468 xmlGenericError(xmlGenericErrorContext, "?attr? ");
469 break;
470 case XML_ENTITY_NODE:
471 xmlGenericError(xmlGenericErrorContext, "?ent? ");
472 break;
473 case XML_DOCUMENT_NODE:
474 xmlGenericError(xmlGenericErrorContext, "?doc? ");
475 break;
476 case XML_DOCUMENT_TYPE_NODE:
477 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
478 break;
479 case XML_DOCUMENT_FRAG_NODE:
480 xmlGenericError(xmlGenericErrorContext, "?frag? ");
481 break;
482 case XML_NOTATION_NODE:
483 xmlGenericError(xmlGenericErrorContext, "?nota? ");
484 break;
485 case XML_HTML_DOCUMENT_NODE:
486 xmlGenericError(xmlGenericErrorContext, "?html? ");
487 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000488#ifdef LIBXML_DOCB_ENABLED
489 case XML_DOCB_DOCUMENT_NODE:
490 xmlGenericError(xmlGenericErrorContext, "?docb? ");
491 break;
492#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000493 case XML_DTD_NODE:
494 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
495 break;
496 case XML_ELEMENT_DECL:
497 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
498 break;
499 case XML_ATTRIBUTE_DECL:
500 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
501 break;
502 case XML_ENTITY_DECL:
503 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
504 break;
505 case XML_NAMESPACE_DECL:
506 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
507 break;
508 case XML_XINCLUDE_START:
509 xmlGenericError(xmlGenericErrorContext, "incstart ");
510 break;
511 case XML_XINCLUDE_END:
512 xmlGenericError(xmlGenericErrorContext, "incend ");
513 break;
514 }
515}
516
517static void
518xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000519 if (cur == NULL)
520 xmlGenericError(xmlGenericErrorContext, "null ");
521 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000522 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000523 cur = cur->next;
524 }
525}
526
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000527static void
528xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000529 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000530
531 expr[0] = 0;
532 xmlGenericError(xmlGenericErrorContext, "valid: ");
533 xmlValidPrintNodeList(cur);
534 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000535 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000536 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
537}
538
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000539static void
540xmlValidDebugState(xmlValidStatePtr state) {
541 xmlGenericError(xmlGenericErrorContext, "(");
542 if (state->cont == NULL)
543 xmlGenericError(xmlGenericErrorContext, "null,");
544 else
545 switch (state->cont->type) {
546 case XML_ELEMENT_CONTENT_PCDATA:
547 xmlGenericError(xmlGenericErrorContext, "pcdata,");
548 break;
549 case XML_ELEMENT_CONTENT_ELEMENT:
550 xmlGenericError(xmlGenericErrorContext, "%s,",
551 state->cont->name);
552 break;
553 case XML_ELEMENT_CONTENT_SEQ:
554 xmlGenericError(xmlGenericErrorContext, "seq,");
555 break;
556 case XML_ELEMENT_CONTENT_OR:
557 xmlGenericError(xmlGenericErrorContext, "or,");
558 break;
559 }
560 xmlValidPrintNode(state->node);
561 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
562 state->depth, state->occurs, state->state);
563}
564
565static void
566xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
567 int i, j;
568
569 xmlGenericError(xmlGenericErrorContext, "state: ");
570 xmlValidDebugState(ctxt->vstate);
571 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
572 ctxt->vstateNr - 1);
573 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
574 xmlValidDebugState(&ctxt->vstateTab[j]);
575 xmlGenericError(xmlGenericErrorContext, "\n");
576}
577
578/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000579#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000580 *****/
581
582#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000583#define DEBUG_VALID_MSG(m) \
584 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
585
Owen Taylor3473f882001-02-23 17:55:21 +0000586#else
587#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000588#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000589#endif
590
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000591/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000592
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000593
Owen Taylor3473f882001-02-23 17:55:21 +0000594#define CHECK_DTD \
595 if (doc == NULL) return(0); \
596 else if ((doc->intSubset == NULL) && \
597 (doc->extSubset == NULL)) return(0)
598
Owen Taylor3473f882001-02-23 17:55:21 +0000599xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
600
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000601#ifdef LIBXML_REGEXP_ENABLED
602
603/************************************************************************
604 * *
605 * Content model validation based on the regexps *
606 * *
607 ************************************************************************/
608
609/**
610 * xmlValidBuildAContentModel:
611 * @content: the content model
612 * @ctxt: the schema parser context
613 * @name: the element name whose content is being built
614 *
615 * Generate the automata sequence needed for that type
616 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000617 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000618 */
619static int
620xmlValidBuildAContentModel(xmlElementContentPtr content,
621 xmlValidCtxtPtr ctxt,
622 const xmlChar *name) {
623 if (content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000624 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
625 "Found NULL content in content model of %s\n",
626 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000627 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000628 }
629 switch (content->type) {
630 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000631 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
632 "Found PCDATA in content model of %s\n",
633 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000634 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000635 break;
636 case XML_ELEMENT_CONTENT_ELEMENT: {
637 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000638 xmlChar fn[50];
639 xmlChar *fullname;
640
641 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
642 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000643 xmlVErrMemory(ctxt, "Building content model");
Daniel Veillardc00cda82003-04-07 10:22:39 +0000644 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000645 }
646
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000647 switch (content->ocur) {
648 case XML_ELEMENT_CONTENT_ONCE:
649 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000650 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000651 break;
652 case XML_ELEMENT_CONTENT_OPT:
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 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
656 break;
657 case XML_ELEMENT_CONTENT_PLUS:
658 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000659 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000660 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000661 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000662 break;
663 case XML_ELEMENT_CONTENT_MULT:
664 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000665 ctxt->state, fullname, NULL);
Daniel Veillard57e79b32003-02-04 15:33:12 +0000666 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
667 NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000668 break;
669 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000670 if ((fullname != fn) && (fullname != content->name))
671 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000672 break;
673 }
674 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000675 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000676 xmlElementContentOccur ocur;
677
678 /*
679 * Simply iterate over the content
680 */
681 oldstate = ctxt->state;
682 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000683 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
684 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
685 oldstate = ctxt->state;
686 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000687 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000688 xmlValidBuildAContentModel(content->c1, ctxt, name);
689 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000690 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
691 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
692 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000693 oldend = ctxt->state;
694 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000695 switch (ocur) {
696 case XML_ELEMENT_CONTENT_ONCE:
697 break;
698 case XML_ELEMENT_CONTENT_OPT:
699 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
700 break;
701 case XML_ELEMENT_CONTENT_MULT:
702 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000703 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000704 break;
705 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000706 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000707 break;
708 }
709 break;
710 }
711 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000712 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000713 xmlElementContentOccur ocur;
714
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000715 ocur = content->ocur;
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000716 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
717 (ocur == XML_ELEMENT_CONTENT_MULT)) {
718 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
719 ctxt->state, NULL);
720 }
721 oldstate = ctxt->state;
722 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000723
724 /*
725 * iterate over the subtypes and remerge the end with an
726 * epsilon transition
727 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000728 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000729 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000730 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000731 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000732 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000733 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
734 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000735 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000736 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000737 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
738 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000739 switch (ocur) {
740 case XML_ELEMENT_CONTENT_ONCE:
741 break;
742 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000743 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000744 break;
745 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000746 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
747 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000748 break;
749 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000750 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000751 break;
752 }
753 break;
754 }
755 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000756 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
757 "ContentModel broken for element %s\n",
758 (const char *) name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000759 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000760 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000761 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000762}
763/**
764 * xmlValidBuildContentModel:
765 * @ctxt: a validation context
766 * @elem: an element declaration node
767 *
768 * (Re)Build the automata associated to the content model of this
769 * element
770 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000771 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000772 */
773int
774xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000775
776 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000777 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000778 if (elem->type != XML_ELEMENT_DECL)
779 return(0);
780 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
781 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000782 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000783 if (elem->contModel != NULL) {
784 if (!xmlRegexpIsDeterminist(elem->contModel)) {
785 ctxt->valid = 0;
786 return(0);
787 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000788 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000789 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000790
791 ctxt->am = xmlNewAutomata();
792 if (ctxt->am == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000793 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
794 XML_ERR_INTERNAL_ERROR,
795 "Cannot create automata for element %s\n",
796 elem->name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000797 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000798 }
William M. Brack78637da2003-07-31 14:47:38 +0000799 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000800 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
801 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000802 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000803 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000804 char expr[5000];
805 expr[0] = 0;
806 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000807 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
808 XML_DTD_CONTENT_NOT_DETERMINIST,
809 "Content model of %s is not determinist: %s\n",
810 elem->name, BAD_CAST expr, NULL);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000811#ifdef DEBUG_REGEXP_ALGO
812 xmlRegexpPrint(stderr, elem->contModel);
813#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000814 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000815 ctxt->state = NULL;
816 xmlFreeAutomata(ctxt->am);
817 ctxt->am = NULL;
818 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000819 }
820 ctxt->state = NULL;
821 xmlFreeAutomata(ctxt->am);
822 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000823 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000824}
825
826#endif /* LIBXML_REGEXP_ENABLED */
827
Owen Taylor3473f882001-02-23 17:55:21 +0000828/****************************************************************
829 * *
830 * Util functions for data allocation/deallocation *
831 * *
832 ****************************************************************/
833
834/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000835 * xmlNewValidCtxt:
836 *
837 * Allocate a validation context structure.
838 *
839 * Returns NULL if not, otherwise the new validation context structure
840 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000841xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000842 xmlValidCtxtPtr ret;
843
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000844 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000845 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000846 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000847 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000848
849 (void) memset(ret, 0, sizeof (xmlValidCtxt));
850
851 return (ret);
852}
853
854/**
855 * xmlFreeValidCtxt:
856 * @cur: the validation context to free
857 *
858 * Free a validation context structure.
859 */
860void
861xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
862 xmlFree(cur);
863}
864
Daniel Veillard4432df22003-09-28 18:58:27 +0000865#endif /* LIBXML_VALID_ENABLED */
866
Daniel Veillarda37aab82003-06-09 09:10:36 +0000867/**
Owen Taylor3473f882001-02-23 17:55:21 +0000868 * xmlNewElementContent:
869 * @name: the subelement name or NULL
870 * @type: the type of element content decl
871 *
872 * Allocate an element content structure.
873 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000874 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000875 */
876xmlElementContentPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000877xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000878 xmlElementContentPtr ret;
879
880 switch(type) {
881 case XML_ELEMENT_CONTENT_ELEMENT:
882 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000883 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
884 "xmlNewElementContent : name == NULL !\n",
885 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000886 }
887 break;
888 case XML_ELEMENT_CONTENT_PCDATA:
889 case XML_ELEMENT_CONTENT_SEQ:
890 case XML_ELEMENT_CONTENT_OR:
891 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000892 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
893 "xmlNewElementContent : name != NULL !\n",
894 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000895 }
896 break;
897 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000898 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
899 "Internal: ELEMENT content corrupted invalid type\n",
900 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000901 return(NULL);
902 }
903 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
904 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000905 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000906 return(NULL);
907 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000908 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000909 ret->type = type;
910 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000911 if (name != NULL) {
912 xmlChar *prefix = NULL;
913 ret->name = xmlSplitQName2(name, &prefix);
914 if (ret->name == NULL)
915 ret->name = xmlStrdup(name);
916 ret->prefix = prefix;
917 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000918 ret->name = NULL;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000919 ret->prefix = NULL;
920 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000921 ret->c1 = ret->c2 = ret->parent = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000922 return(ret);
923}
924
925/**
926 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000927 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +0000928 *
929 * Build a copy of an element content description.
930 *
931 * Returns the new xmlElementContentPtr or NULL in case of error.
932 */
933xmlElementContentPtr
934xmlCopyElementContent(xmlElementContentPtr cur) {
935 xmlElementContentPtr ret;
936
937 if (cur == NULL) return(NULL);
938 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
939 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000940 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000941 return(NULL);
942 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000943 if (cur->prefix != NULL)
944 ret->prefix = xmlStrdup(cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000945 ret->ocur = cur->ocur;
946 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000947 if (ret->c1 != NULL)
948 ret->c1->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000949 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000950 if (ret->c2 != NULL)
951 ret->c2->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000952 return(ret);
953}
954
955/**
956 * xmlFreeElementContent:
957 * @cur: the element content tree to free
958 *
959 * Free an element content structure. This is a recursive call !
960 */
961void
962xmlFreeElementContent(xmlElementContentPtr cur) {
963 if (cur == NULL) return;
964 switch (cur->type) {
965 case XML_ELEMENT_CONTENT_PCDATA:
966 case XML_ELEMENT_CONTENT_ELEMENT:
967 case XML_ELEMENT_CONTENT_SEQ:
968 case XML_ELEMENT_CONTENT_OR:
969 break;
970 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000971 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
972 "Internal: ELEMENT content corrupted invalid type\n",
973 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000974 return;
975 }
976 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
977 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
978 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000979 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000980 xmlFree(cur);
981}
982
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000983#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000984/**
985 * xmlDumpElementContent:
986 * @buf: An XML buffer
987 * @content: An element table
988 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
989 *
990 * This will dump the content of the element table as an XML DTD definition
991 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000992static void
Owen Taylor3473f882001-02-23 17:55:21 +0000993xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
994 if (content == NULL) return;
995
996 if (glob) xmlBufferWriteChar(buf, "(");
997 switch (content->type) {
998 case XML_ELEMENT_CONTENT_PCDATA:
999 xmlBufferWriteChar(buf, "#PCDATA");
1000 break;
1001 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001002 if (content->prefix != NULL) {
1003 xmlBufferWriteCHAR(buf, content->prefix);
1004 xmlBufferWriteChar(buf, ":");
1005 }
Owen Taylor3473f882001-02-23 17:55:21 +00001006 xmlBufferWriteCHAR(buf, content->name);
1007 break;
1008 case XML_ELEMENT_CONTENT_SEQ:
1009 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1010 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1011 xmlDumpElementContent(buf, content->c1, 1);
1012 else
1013 xmlDumpElementContent(buf, content->c1, 0);
1014 xmlBufferWriteChar(buf, " , ");
1015 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
1016 xmlDumpElementContent(buf, content->c2, 1);
1017 else
1018 xmlDumpElementContent(buf, content->c2, 0);
1019 break;
1020 case XML_ELEMENT_CONTENT_OR:
1021 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1022 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1023 xmlDumpElementContent(buf, content->c1, 1);
1024 else
1025 xmlDumpElementContent(buf, content->c1, 0);
1026 xmlBufferWriteChar(buf, " | ");
1027 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
1028 xmlDumpElementContent(buf, content->c2, 1);
1029 else
1030 xmlDumpElementContent(buf, content->c2, 0);
1031 break;
1032 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001033 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1034 "Internal: ELEMENT content corrupted invalid type\n",
1035 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001036 }
1037 if (glob)
1038 xmlBufferWriteChar(buf, ")");
1039 switch (content->ocur) {
1040 case XML_ELEMENT_CONTENT_ONCE:
1041 break;
1042 case XML_ELEMENT_CONTENT_OPT:
1043 xmlBufferWriteChar(buf, "?");
1044 break;
1045 case XML_ELEMENT_CONTENT_MULT:
1046 xmlBufferWriteChar(buf, "*");
1047 break;
1048 case XML_ELEMENT_CONTENT_PLUS:
1049 xmlBufferWriteChar(buf, "+");
1050 break;
1051 }
1052}
1053
1054/**
1055 * xmlSprintfElementContent:
1056 * @buf: an output buffer
1057 * @content: An element table
1058 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1059 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001060 * Deprecated, unsafe, use xmlSnprintfElementContent
1061 */
1062void
1063xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1064 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1065 int glob ATTRIBUTE_UNUSED) {
1066}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001067#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001068
1069/**
1070 * xmlSnprintfElementContent:
1071 * @buf: an output buffer
1072 * @size: the buffer size
1073 * @content: An element table
1074 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1075 *
Owen Taylor3473f882001-02-23 17:55:21 +00001076 * This will dump the content of the element content definition
1077 * Intended just for the debug routine
1078 */
1079void
Daniel Veillardd3d06722001-08-15 12:06:36 +00001080xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int glob) {
1081 int len;
1082
Owen Taylor3473f882001-02-23 17:55:21 +00001083 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001084 len = strlen(buf);
1085 if (size - len < 50) {
1086 if ((size - len > 4) && (buf[len - 1] != '.'))
1087 strcat(buf, " ...");
1088 return;
1089 }
Owen Taylor3473f882001-02-23 17:55:21 +00001090 if (glob) strcat(buf, "(");
1091 switch (content->type) {
1092 case XML_ELEMENT_CONTENT_PCDATA:
1093 strcat(buf, "#PCDATA");
1094 break;
1095 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001096 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001097 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001098 strcat(buf, " ...");
1099 return;
1100 }
1101 strcat(buf, (char *) content->prefix);
1102 strcat(buf, ":");
1103 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001104 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001105 strcat(buf, " ...");
1106 return;
1107 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001108 if (content->name != NULL)
1109 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001110 break;
1111 case XML_ELEMENT_CONTENT_SEQ:
1112 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1113 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001114 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001115 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001116 xmlSnprintfElementContent(buf, size, content->c1, 0);
1117 len = strlen(buf);
1118 if (size - len < 50) {
1119 if ((size - len > 4) && (buf[len - 1] != '.'))
1120 strcat(buf, " ...");
1121 return;
1122 }
Owen Taylor3473f882001-02-23 17:55:21 +00001123 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001124 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1125 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1126 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001127 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001128 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001129 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001130 break;
1131 case XML_ELEMENT_CONTENT_OR:
1132 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1133 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001134 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001135 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001136 xmlSnprintfElementContent(buf, size, content->c1, 0);
1137 len = strlen(buf);
1138 if (size - len < 50) {
1139 if ((size - len > 4) && (buf[len - 1] != '.'))
1140 strcat(buf, " ...");
1141 return;
1142 }
Owen Taylor3473f882001-02-23 17:55:21 +00001143 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001144 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1145 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1146 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001147 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001148 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001149 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001150 break;
1151 }
1152 if (glob)
1153 strcat(buf, ")");
1154 switch (content->ocur) {
1155 case XML_ELEMENT_CONTENT_ONCE:
1156 break;
1157 case XML_ELEMENT_CONTENT_OPT:
1158 strcat(buf, "?");
1159 break;
1160 case XML_ELEMENT_CONTENT_MULT:
1161 strcat(buf, "*");
1162 break;
1163 case XML_ELEMENT_CONTENT_PLUS:
1164 strcat(buf, "+");
1165 break;
1166 }
1167}
1168
1169/****************************************************************
1170 * *
1171 * Registration of DTD declarations *
1172 * *
1173 ****************************************************************/
1174
1175/**
1176 * xmlCreateElementTable:
1177 *
1178 * create and initialize an empty element hash table.
1179 *
1180 * Returns the xmlElementTablePtr just created or NULL in case of error.
1181 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001182static xmlElementTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001183xmlCreateElementTable(void) {
1184 return(xmlHashCreate(0));
1185}
1186
1187/**
1188 * xmlFreeElement:
1189 * @elem: An element
1190 *
1191 * Deallocate the memory used by an element definition
1192 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001193static void
Owen Taylor3473f882001-02-23 17:55:21 +00001194xmlFreeElement(xmlElementPtr elem) {
1195 if (elem == NULL) return;
1196 xmlUnlinkNode((xmlNodePtr) elem);
1197 xmlFreeElementContent(elem->content);
1198 if (elem->name != NULL)
1199 xmlFree((xmlChar *) elem->name);
1200 if (elem->prefix != NULL)
1201 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001202#ifdef LIBXML_REGEXP_ENABLED
1203 if (elem->contModel != NULL)
1204 xmlRegFreeRegexp(elem->contModel);
1205#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001206 xmlFree(elem);
1207}
1208
1209
1210/**
1211 * xmlAddElementDecl:
1212 * @ctxt: the validation context
1213 * @dtd: pointer to the DTD
1214 * @name: the entity name
1215 * @type: the element type
1216 * @content: the element content tree or NULL
1217 *
1218 * Register a new element declaration
1219 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001220 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001221 */
1222xmlElementPtr
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001223xmlAddElementDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1224 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001225 xmlElementTypeVal type,
1226 xmlElementContentPtr content) {
1227 xmlElementPtr ret;
1228 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001229 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001230 xmlChar *ns, *uqname;
1231
1232 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001233 return(NULL);
1234 }
1235 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001236 return(NULL);
1237 }
1238 switch (type) {
1239 case XML_ELEMENT_TYPE_EMPTY:
1240 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001241 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1242 "xmlAddElementDecl: content != NULL for EMPTY\n",
1243 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001244 return(NULL);
1245 }
1246 break;
1247 case XML_ELEMENT_TYPE_ANY:
1248 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001249 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1250 "xmlAddElementDecl: content != NULL for ANY\n",
1251 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001252 return(NULL);
1253 }
1254 break;
1255 case XML_ELEMENT_TYPE_MIXED:
1256 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001257 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1258 "xmlAddElementDecl: content == NULL for MIXED\n",
1259 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001260 return(NULL);
1261 }
1262 break;
1263 case XML_ELEMENT_TYPE_ELEMENT:
1264 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001265 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1266 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1267 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001268 return(NULL);
1269 }
1270 break;
1271 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001272 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1273 "Internal: ELEMENT decl corrupted invalid type\n",
1274 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001275 return(NULL);
1276 }
1277
1278 /*
1279 * check if name is a QName
1280 */
1281 uqname = xmlSplitQName2(name, &ns);
1282 if (uqname != NULL)
1283 name = uqname;
1284
1285 /*
1286 * Create the Element table if needed.
1287 */
1288 table = (xmlElementTablePtr) dtd->elements;
1289 if (table == NULL) {
1290 table = xmlCreateElementTable();
1291 dtd->elements = (void *) table;
1292 }
1293 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001294 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001295 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001296 if (uqname != NULL)
1297 xmlFree(uqname);
1298 if (ns != NULL)
1299 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001300 return(NULL);
1301 }
1302
Daniel Veillarda10efa82001-04-18 13:09:01 +00001303 /*
1304 * lookup old attributes inserted on an undefined element in the
1305 * internal subset.
1306 */
1307 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1308 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1309 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1310 oldAttributes = ret->attributes;
1311 ret->attributes = NULL;
1312 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1313 xmlFreeElement(ret);
1314 }
Owen Taylor3473f882001-02-23 17:55:21 +00001315 }
Owen Taylor3473f882001-02-23 17:55:21 +00001316
1317 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001318 * The element may already be present if one of its attribute
1319 * was registered first
1320 */
1321 ret = xmlHashLookup2(table, name, ns);
1322 if (ret != NULL) {
1323 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001324#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001325 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001326 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001327 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001328 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1329 "Redefinition of element %s\n",
1330 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001331#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001332 if (uqname != NULL)
1333 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001334 if (ns != NULL)
1335 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001336 return(NULL);
1337 }
1338 } else {
1339 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1340 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001341 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001342 if (uqname != NULL)
1343 xmlFree(uqname);
1344 if (ns != NULL)
1345 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001346 return(NULL);
1347 }
1348 memset(ret, 0, sizeof(xmlElement));
1349 ret->type = XML_ELEMENT_DECL;
1350
1351 /*
1352 * fill the structure.
1353 */
1354 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001355 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001356 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001357 if (uqname != NULL)
1358 xmlFree(uqname);
1359 if (ns != NULL)
1360 xmlFree(ns);
1361 xmlFree(ret);
1362 return(NULL);
1363 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001364 ret->prefix = ns;
1365
1366 /*
1367 * Validity Check:
1368 * Insertion must not fail
1369 */
1370 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001371#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001372 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001373 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001374 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001375 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1376 "Redefinition of element %s\n",
1377 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001378#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001379 xmlFreeElement(ret);
1380 if (uqname != NULL)
1381 xmlFree(uqname);
1382 return(NULL);
1383 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001384 /*
1385 * For new element, may have attributes from earlier
1386 * definition in internal subset
1387 */
1388 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001389 }
1390
1391 /*
1392 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001393 */
1394 ret->etype = type;
Owen Taylor3473f882001-02-23 17:55:21 +00001395 ret->content = xmlCopyElementContent(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001396
1397 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001398 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001399 */
1400 ret->parent = dtd;
1401 ret->doc = dtd->doc;
1402 if (dtd->last == NULL) {
1403 dtd->children = dtd->last = (xmlNodePtr) ret;
1404 } else {
1405 dtd->last->next = (xmlNodePtr) ret;
1406 ret->prev = dtd->last;
1407 dtd->last = (xmlNodePtr) ret;
1408 }
1409 if (uqname != NULL)
1410 xmlFree(uqname);
1411 return(ret);
1412}
1413
1414/**
1415 * xmlFreeElementTable:
1416 * @table: An element table
1417 *
1418 * Deallocate the memory used by an element hash table.
1419 */
1420void
1421xmlFreeElementTable(xmlElementTablePtr table) {
1422 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1423}
1424
Daniel Veillard652327a2003-09-29 18:02:38 +00001425#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001426/**
1427 * xmlCopyElement:
1428 * @elem: An element
1429 *
1430 * Build a copy of an element.
1431 *
1432 * Returns the new xmlElementPtr or NULL in case of error.
1433 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001434static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001435xmlCopyElement(xmlElementPtr elem) {
1436 xmlElementPtr cur;
1437
1438 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1439 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001440 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001441 return(NULL);
1442 }
1443 memset(cur, 0, sizeof(xmlElement));
1444 cur->type = XML_ELEMENT_DECL;
1445 cur->etype = elem->etype;
1446 if (elem->name != NULL)
1447 cur->name = xmlStrdup(elem->name);
1448 else
1449 cur->name = NULL;
1450 if (elem->prefix != NULL)
1451 cur->prefix = xmlStrdup(elem->prefix);
1452 else
1453 cur->prefix = NULL;
1454 cur->content = xmlCopyElementContent(elem->content);
1455 /* TODO : rebuild the attribute list on the copy */
1456 cur->attributes = NULL;
1457 return(cur);
1458}
1459
1460/**
1461 * xmlCopyElementTable:
1462 * @table: An element table
1463 *
1464 * Build a copy of an element table.
1465 *
1466 * Returns the new xmlElementTablePtr or NULL in case of error.
1467 */
1468xmlElementTablePtr
1469xmlCopyElementTable(xmlElementTablePtr table) {
1470 return((xmlElementTablePtr) xmlHashCopy(table,
1471 (xmlHashCopier) xmlCopyElement));
1472}
Daniel Veillard652327a2003-09-29 18:02:38 +00001473#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001474
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001475#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001476/**
1477 * xmlDumpElementDecl:
1478 * @buf: the XML buffer output
1479 * @elem: An element table
1480 *
1481 * This will dump the content of the element declaration as an XML
1482 * DTD definition
1483 */
1484void
1485xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1486 switch (elem->etype) {
1487 case XML_ELEMENT_TYPE_EMPTY:
1488 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001489 if (elem->prefix != NULL) {
1490 xmlBufferWriteCHAR(buf, elem->prefix);
1491 xmlBufferWriteChar(buf, ":");
1492 }
Owen Taylor3473f882001-02-23 17:55:21 +00001493 xmlBufferWriteCHAR(buf, elem->name);
1494 xmlBufferWriteChar(buf, " EMPTY>\n");
1495 break;
1496 case XML_ELEMENT_TYPE_ANY:
1497 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001498 if (elem->prefix != NULL) {
1499 xmlBufferWriteCHAR(buf, elem->prefix);
1500 xmlBufferWriteChar(buf, ":");
1501 }
Owen Taylor3473f882001-02-23 17:55:21 +00001502 xmlBufferWriteCHAR(buf, elem->name);
1503 xmlBufferWriteChar(buf, " ANY>\n");
1504 break;
1505 case XML_ELEMENT_TYPE_MIXED:
1506 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001507 if (elem->prefix != NULL) {
1508 xmlBufferWriteCHAR(buf, elem->prefix);
1509 xmlBufferWriteChar(buf, ":");
1510 }
Owen Taylor3473f882001-02-23 17:55:21 +00001511 xmlBufferWriteCHAR(buf, elem->name);
1512 xmlBufferWriteChar(buf, " ");
1513 xmlDumpElementContent(buf, elem->content, 1);
1514 xmlBufferWriteChar(buf, ">\n");
1515 break;
1516 case XML_ELEMENT_TYPE_ELEMENT:
1517 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001518 if (elem->prefix != NULL) {
1519 xmlBufferWriteCHAR(buf, elem->prefix);
1520 xmlBufferWriteChar(buf, ":");
1521 }
Owen Taylor3473f882001-02-23 17:55:21 +00001522 xmlBufferWriteCHAR(buf, elem->name);
1523 xmlBufferWriteChar(buf, " ");
1524 xmlDumpElementContent(buf, elem->content, 1);
1525 xmlBufferWriteChar(buf, ">\n");
1526 break;
1527 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001528 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1529 "Internal: ELEMENT struct corrupted invalid type\n",
1530 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001531 }
1532}
1533
1534/**
1535 * xmlDumpElementTable:
1536 * @buf: the XML buffer output
1537 * @table: An element table
1538 *
1539 * This will dump the content of the element table as an XML DTD definition
1540 */
1541void
1542xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1543 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDecl, buf);
1544}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001545#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001546
1547/**
1548 * xmlCreateEnumeration:
1549 * @name: the enumeration name or NULL
1550 *
1551 * create and initialize an enumeration attribute node.
1552 *
1553 * Returns the xmlEnumerationPtr just created or NULL in case
1554 * of error.
1555 */
1556xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001557xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001558 xmlEnumerationPtr ret;
1559
1560 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1561 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001562 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001563 return(NULL);
1564 }
1565 memset(ret, 0, sizeof(xmlEnumeration));
1566
1567 if (name != NULL)
1568 ret->name = xmlStrdup(name);
1569 return(ret);
1570}
1571
1572/**
1573 * xmlFreeEnumeration:
1574 * @cur: the tree to free.
1575 *
1576 * free an enumeration attribute node (recursive).
1577 */
1578void
1579xmlFreeEnumeration(xmlEnumerationPtr cur) {
1580 if (cur == NULL) return;
1581
1582 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1583
1584 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001585 xmlFree(cur);
1586}
1587
Daniel Veillard652327a2003-09-29 18:02:38 +00001588#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001589/**
1590 * xmlCopyEnumeration:
1591 * @cur: the tree to copy.
1592 *
1593 * Copy an enumeration attribute node (recursive).
1594 *
1595 * Returns the xmlEnumerationPtr just created or NULL in case
1596 * of error.
1597 */
1598xmlEnumerationPtr
1599xmlCopyEnumeration(xmlEnumerationPtr cur) {
1600 xmlEnumerationPtr ret;
1601
1602 if (cur == NULL) return(NULL);
1603 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1604
1605 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1606 else ret->next = NULL;
1607
1608 return(ret);
1609}
Daniel Veillard652327a2003-09-29 18:02:38 +00001610#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001611
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001612#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001613/**
1614 * xmlDumpEnumeration:
1615 * @buf: the XML buffer output
1616 * @enum: An enumeration
1617 *
1618 * This will dump the content of the enumeration
1619 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001620static void
Owen Taylor3473f882001-02-23 17:55:21 +00001621xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1622 if (cur == NULL) return;
1623
1624 xmlBufferWriteCHAR(buf, cur->name);
1625 if (cur->next == NULL)
1626 xmlBufferWriteChar(buf, ")");
1627 else {
1628 xmlBufferWriteChar(buf, " | ");
1629 xmlDumpEnumeration(buf, cur->next);
1630 }
1631}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001632#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001633
1634/**
1635 * xmlCreateAttributeTable:
1636 *
1637 * create and initialize an empty attribute hash table.
1638 *
1639 * Returns the xmlAttributeTablePtr just created or NULL in case
1640 * of error.
1641 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001642static xmlAttributeTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001643xmlCreateAttributeTable(void) {
1644 return(xmlHashCreate(0));
1645}
1646
Daniel Veillard4432df22003-09-28 18:58:27 +00001647#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001648/**
1649 * xmlScanAttributeDeclCallback:
1650 * @attr: the attribute decl
1651 * @list: the list to update
1652 *
1653 * Callback called by xmlScanAttributeDecl when a new attribute
1654 * has to be entered in the list.
1655 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001656static void
Owen Taylor3473f882001-02-23 17:55:21 +00001657xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001658 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001659 attr->nexth = *list;
1660 *list = attr;
1661}
1662
1663/**
1664 * xmlScanAttributeDecl:
1665 * @dtd: pointer to the DTD
1666 * @elem: the element name
1667 *
1668 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001669 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001670 *
1671 * Returns the pointer to the first attribute decl in the chain,
1672 * possibly NULL.
1673 */
1674xmlAttributePtr
1675xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1676 xmlAttributePtr ret = NULL;
1677 xmlAttributeTablePtr table;
1678
1679 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001680 return(NULL);
1681 }
1682 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001683 return(NULL);
1684 }
1685 table = (xmlAttributeTablePtr) dtd->attributes;
1686 if (table == NULL)
1687 return(NULL);
1688
1689 /* WRONG !!! */
1690 xmlHashScan3(table, NULL, NULL, elem,
1691 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1692 return(ret);
1693}
1694
1695/**
1696 * xmlScanIDAttributeDecl:
1697 * @ctxt: the validation context
1698 * @elem: the element name
1699 *
1700 * Verify that the element don't have too many ID attributes
1701 * declared.
1702 *
1703 * Returns the number of ID attributes found.
1704 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001705static int
Owen Taylor3473f882001-02-23 17:55:21 +00001706xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1707 xmlAttributePtr cur;
1708 int ret = 0;
1709
1710 if (elem == NULL) return(0);
1711 cur = elem->attributes;
1712 while (cur != NULL) {
1713 if (cur->atype == XML_ATTRIBUTE_ID) {
1714 ret ++;
1715 if (ret > 1)
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001716 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001717 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001718 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001719 }
1720 cur = cur->nexth;
1721 }
1722 return(ret);
1723}
Daniel Veillard4432df22003-09-28 18:58:27 +00001724#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001725
1726/**
1727 * xmlFreeAttribute:
1728 * @elem: An attribute
1729 *
1730 * Deallocate the memory used by an attribute definition
1731 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001732static void
Owen Taylor3473f882001-02-23 17:55:21 +00001733xmlFreeAttribute(xmlAttributePtr attr) {
1734 if (attr == NULL) return;
1735 xmlUnlinkNode((xmlNodePtr) attr);
1736 if (attr->tree != NULL)
1737 xmlFreeEnumeration(attr->tree);
1738 if (attr->elem != NULL)
1739 xmlFree((xmlChar *) attr->elem);
1740 if (attr->name != NULL)
1741 xmlFree((xmlChar *) attr->name);
1742 if (attr->defaultValue != NULL)
1743 xmlFree((xmlChar *) attr->defaultValue);
1744 if (attr->prefix != NULL)
1745 xmlFree((xmlChar *) attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001746 xmlFree(attr);
1747}
1748
1749
1750/**
1751 * xmlAddAttributeDecl:
1752 * @ctxt: the validation context
1753 * @dtd: pointer to the DTD
1754 * @elem: the element name
1755 * @name: the attribute name
1756 * @ns: the attribute namespace prefix
1757 * @type: the attribute type
1758 * @def: the attribute default type
1759 * @defaultValue: the attribute default value
1760 * @tree: if it's an enumeration, the associated list
1761 *
1762 * Register a new attribute declaration
1763 * Note that @tree becomes the ownership of the DTD
1764 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001765 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001766 */
1767xmlAttributePtr
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001768xmlAddAttributeDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1769 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001770 const xmlChar *name, const xmlChar *ns,
1771 xmlAttributeType type, xmlAttributeDefault def,
1772 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1773 xmlAttributePtr ret;
1774 xmlAttributeTablePtr table;
1775 xmlElementPtr elemDef;
1776
1777 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001778 xmlFreeEnumeration(tree);
1779 return(NULL);
1780 }
1781 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001782 xmlFreeEnumeration(tree);
1783 return(NULL);
1784 }
1785 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001786 xmlFreeEnumeration(tree);
1787 return(NULL);
1788 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001789
Daniel Veillard4432df22003-09-28 18:58:27 +00001790#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001791 /*
1792 * Check the type and possibly the default value.
1793 */
1794 switch (type) {
1795 case XML_ATTRIBUTE_CDATA:
1796 break;
1797 case XML_ATTRIBUTE_ID:
1798 break;
1799 case XML_ATTRIBUTE_IDREF:
1800 break;
1801 case XML_ATTRIBUTE_IDREFS:
1802 break;
1803 case XML_ATTRIBUTE_ENTITY:
1804 break;
1805 case XML_ATTRIBUTE_ENTITIES:
1806 break;
1807 case XML_ATTRIBUTE_NMTOKEN:
1808 break;
1809 case XML_ATTRIBUTE_NMTOKENS:
1810 break;
1811 case XML_ATTRIBUTE_ENUMERATION:
1812 break;
1813 case XML_ATTRIBUTE_NOTATION:
1814 break;
1815 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001816 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1817 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1818 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001819 xmlFreeEnumeration(tree);
1820 return(NULL);
1821 }
1822 if ((defaultValue != NULL) &&
1823 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001824 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1825 "Attribute %s of %s: invalid default value\n",
1826 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00001827 defaultValue = NULL;
Daniel Veillardd01fd3e2002-02-18 22:27:47 +00001828 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001829 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001830#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001831
1832 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001833 * Check first that an attribute defined in the external subset wasn't
1834 * already defined in the internal subset
1835 */
1836 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1837 (dtd->doc->intSubset != NULL) &&
1838 (dtd->doc->intSubset->attributes != NULL)) {
1839 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1840 if (ret != NULL)
1841 return(NULL);
1842 }
1843
1844 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001845 * Create the Attribute table if needed.
1846 */
1847 table = (xmlAttributeTablePtr) dtd->attributes;
1848 if (table == NULL) {
1849 table = xmlCreateAttributeTable();
1850 dtd->attributes = (void *) table;
1851 }
1852 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001853 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001854 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001855 return(NULL);
1856 }
1857
1858
1859 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1860 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001861 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001862 return(NULL);
1863 }
1864 memset(ret, 0, sizeof(xmlAttribute));
1865 ret->type = XML_ATTRIBUTE_DECL;
1866
1867 /*
1868 * fill the structure.
1869 */
1870 ret->atype = type;
1871 ret->name = xmlStrdup(name);
1872 ret->prefix = xmlStrdup(ns);
1873 ret->elem = xmlStrdup(elem);
1874 ret->def = def;
1875 ret->tree = tree;
1876 if (defaultValue != NULL)
1877 ret->defaultValue = xmlStrdup(defaultValue);
1878
1879 /*
1880 * Validity Check:
1881 * Search the DTD for previous declarations of the ATTLIST
1882 */
1883 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001884#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001885 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001886 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00001887 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001888 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00001889 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001890 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001891#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001892 xmlFreeAttribute(ret);
1893 return(NULL);
1894 }
1895
1896 /*
1897 * Validity Check:
1898 * Multiple ID per element
1899 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001900 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001901 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00001902
Daniel Veillard4432df22003-09-28 18:58:27 +00001903#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001904 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00001905 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001906 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00001907 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001908 elem, name, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00001909 ctxt->valid = 0;
1910 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001911#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00001912
Daniel Veillard48da9102001-08-07 01:10:10 +00001913 /*
1914 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001915 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00001916 */
1917 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1918 ((ret->prefix != NULL &&
1919 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1920 ret->nexth = elemDef->attributes;
1921 elemDef->attributes = ret;
1922 } else {
1923 xmlAttributePtr tmp = elemDef->attributes;
1924
1925 while ((tmp != NULL) &&
1926 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1927 ((ret->prefix != NULL &&
1928 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1929 if (tmp->nexth == NULL)
1930 break;
1931 tmp = tmp->nexth;
1932 }
1933 if (tmp != NULL) {
1934 ret->nexth = tmp->nexth;
1935 tmp->nexth = ret;
1936 } else {
1937 ret->nexth = elemDef->attributes;
1938 elemDef->attributes = ret;
1939 }
1940 }
Owen Taylor3473f882001-02-23 17:55:21 +00001941 }
1942
1943 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001944 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001945 */
1946 ret->parent = dtd;
1947 ret->doc = dtd->doc;
1948 if (dtd->last == NULL) {
1949 dtd->children = dtd->last = (xmlNodePtr) ret;
1950 } else {
1951 dtd->last->next = (xmlNodePtr) ret;
1952 ret->prev = dtd->last;
1953 dtd->last = (xmlNodePtr) ret;
1954 }
1955 return(ret);
1956}
1957
1958/**
1959 * xmlFreeAttributeTable:
1960 * @table: An attribute table
1961 *
1962 * Deallocate the memory used by an entities hash table.
1963 */
1964void
1965xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1966 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
1967}
1968
Daniel Veillard652327a2003-09-29 18:02:38 +00001969#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001970/**
1971 * xmlCopyAttribute:
1972 * @attr: An attribute
1973 *
1974 * Build a copy of an attribute.
1975 *
1976 * Returns the new xmlAttributePtr or NULL in case of error.
1977 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001978static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001979xmlCopyAttribute(xmlAttributePtr attr) {
1980 xmlAttributePtr cur;
1981
1982 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1983 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001984 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001985 return(NULL);
1986 }
1987 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00001988 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00001989 cur->atype = attr->atype;
1990 cur->def = attr->def;
1991 cur->tree = xmlCopyEnumeration(attr->tree);
1992 if (attr->elem != NULL)
1993 cur->elem = xmlStrdup(attr->elem);
1994 if (attr->name != NULL)
1995 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00001996 if (attr->prefix != NULL)
1997 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001998 if (attr->defaultValue != NULL)
1999 cur->defaultValue = xmlStrdup(attr->defaultValue);
2000 return(cur);
2001}
2002
2003/**
2004 * xmlCopyAttributeTable:
2005 * @table: An attribute table
2006 *
2007 * Build a copy of an attribute table.
2008 *
2009 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2010 */
2011xmlAttributeTablePtr
2012xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2013 return((xmlAttributeTablePtr) xmlHashCopy(table,
2014 (xmlHashCopier) xmlCopyAttribute));
2015}
Daniel Veillard652327a2003-09-29 18:02:38 +00002016#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002017
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002018#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002019/**
2020 * xmlDumpAttributeDecl:
2021 * @buf: the XML buffer output
2022 * @attr: An attribute declaration
2023 *
2024 * This will dump the content of the attribute declaration as an XML
2025 * DTD definition
2026 */
2027void
2028xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2029 xmlBufferWriteChar(buf, "<!ATTLIST ");
2030 xmlBufferWriteCHAR(buf, attr->elem);
2031 xmlBufferWriteChar(buf, " ");
2032 if (attr->prefix != NULL) {
2033 xmlBufferWriteCHAR(buf, attr->prefix);
2034 xmlBufferWriteChar(buf, ":");
2035 }
2036 xmlBufferWriteCHAR(buf, attr->name);
2037 switch (attr->atype) {
2038 case XML_ATTRIBUTE_CDATA:
2039 xmlBufferWriteChar(buf, " CDATA");
2040 break;
2041 case XML_ATTRIBUTE_ID:
2042 xmlBufferWriteChar(buf, " ID");
2043 break;
2044 case XML_ATTRIBUTE_IDREF:
2045 xmlBufferWriteChar(buf, " IDREF");
2046 break;
2047 case XML_ATTRIBUTE_IDREFS:
2048 xmlBufferWriteChar(buf, " IDREFS");
2049 break;
2050 case XML_ATTRIBUTE_ENTITY:
2051 xmlBufferWriteChar(buf, " ENTITY");
2052 break;
2053 case XML_ATTRIBUTE_ENTITIES:
2054 xmlBufferWriteChar(buf, " ENTITIES");
2055 break;
2056 case XML_ATTRIBUTE_NMTOKEN:
2057 xmlBufferWriteChar(buf, " NMTOKEN");
2058 break;
2059 case XML_ATTRIBUTE_NMTOKENS:
2060 xmlBufferWriteChar(buf, " NMTOKENS");
2061 break;
2062 case XML_ATTRIBUTE_ENUMERATION:
2063 xmlBufferWriteChar(buf, " (");
2064 xmlDumpEnumeration(buf, attr->tree);
2065 break;
2066 case XML_ATTRIBUTE_NOTATION:
2067 xmlBufferWriteChar(buf, " NOTATION (");
2068 xmlDumpEnumeration(buf, attr->tree);
2069 break;
2070 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002071 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2072 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2073 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002074 }
2075 switch (attr->def) {
2076 case XML_ATTRIBUTE_NONE:
2077 break;
2078 case XML_ATTRIBUTE_REQUIRED:
2079 xmlBufferWriteChar(buf, " #REQUIRED");
2080 break;
2081 case XML_ATTRIBUTE_IMPLIED:
2082 xmlBufferWriteChar(buf, " #IMPLIED");
2083 break;
2084 case XML_ATTRIBUTE_FIXED:
2085 xmlBufferWriteChar(buf, " #FIXED");
2086 break;
2087 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002088 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2089 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2090 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002091 }
2092 if (attr->defaultValue != NULL) {
2093 xmlBufferWriteChar(buf, " ");
2094 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2095 }
2096 xmlBufferWriteChar(buf, ">\n");
2097}
2098
2099/**
2100 * xmlDumpAttributeTable:
2101 * @buf: the XML buffer output
2102 * @table: An attribute table
2103 *
2104 * This will dump the content of the attribute table as an XML DTD definition
2105 */
2106void
2107xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
2108 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDecl, buf);
2109}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002110#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002111
2112/************************************************************************
2113 * *
2114 * NOTATIONs *
2115 * *
2116 ************************************************************************/
2117/**
2118 * xmlCreateNotationTable:
2119 *
2120 * create and initialize an empty notation hash table.
2121 *
2122 * Returns the xmlNotationTablePtr just created or NULL in case
2123 * of error.
2124 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002125static xmlNotationTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002126xmlCreateNotationTable(void) {
2127 return(xmlHashCreate(0));
2128}
2129
2130/**
2131 * xmlFreeNotation:
2132 * @not: A notation
2133 *
2134 * Deallocate the memory used by an notation definition
2135 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002136static void
Owen Taylor3473f882001-02-23 17:55:21 +00002137xmlFreeNotation(xmlNotationPtr nota) {
2138 if (nota == NULL) return;
2139 if (nota->name != NULL)
2140 xmlFree((xmlChar *) nota->name);
2141 if (nota->PublicID != NULL)
2142 xmlFree((xmlChar *) nota->PublicID);
2143 if (nota->SystemID != NULL)
2144 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002145 xmlFree(nota);
2146}
2147
2148
2149/**
2150 * xmlAddNotationDecl:
2151 * @dtd: pointer to the DTD
2152 * @ctxt: the validation context
2153 * @name: the entity name
2154 * @PublicID: the public identifier or NULL
2155 * @SystemID: the system identifier or NULL
2156 *
2157 * Register a new notation declaration
2158 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002159 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002160 */
2161xmlNotationPtr
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00002162xmlAddNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002163 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002164 const xmlChar *PublicID, const xmlChar *SystemID) {
2165 xmlNotationPtr ret;
2166 xmlNotationTablePtr table;
2167
2168 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002169 return(NULL);
2170 }
2171 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002172 return(NULL);
2173 }
2174 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002175 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002176 }
2177
2178 /*
2179 * Create the Notation table if needed.
2180 */
2181 table = (xmlNotationTablePtr) dtd->notations;
2182 if (table == NULL)
2183 dtd->notations = table = xmlCreateNotationTable();
2184 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002185 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002186 "xmlAddNotationDecl: Table creation failed!\n");
2187 return(NULL);
2188 }
2189
2190 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2191 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002192 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002193 return(NULL);
2194 }
2195 memset(ret, 0, sizeof(xmlNotation));
2196
2197 /*
2198 * fill the structure.
2199 */
2200 ret->name = xmlStrdup(name);
2201 if (SystemID != NULL)
2202 ret->SystemID = xmlStrdup(SystemID);
2203 if (PublicID != NULL)
2204 ret->PublicID = xmlStrdup(PublicID);
2205
2206 /*
2207 * Validity Check:
2208 * Check the DTD for previous declarations of the ATTLIST
2209 */
2210 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002211#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002212 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2213 "xmlAddNotationDecl: %s already defined\n",
2214 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002215#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002216 xmlFreeNotation(ret);
2217 return(NULL);
2218 }
2219 return(ret);
2220}
2221
2222/**
2223 * xmlFreeNotationTable:
2224 * @table: An notation table
2225 *
2226 * Deallocate the memory used by an entities hash table.
2227 */
2228void
2229xmlFreeNotationTable(xmlNotationTablePtr table) {
2230 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2231}
2232
Daniel Veillard652327a2003-09-29 18:02:38 +00002233#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002234/**
2235 * xmlCopyNotation:
2236 * @nota: A notation
2237 *
2238 * Build a copy of a notation.
2239 *
2240 * Returns the new xmlNotationPtr or NULL in case of error.
2241 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002242static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002243xmlCopyNotation(xmlNotationPtr nota) {
2244 xmlNotationPtr cur;
2245
2246 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2247 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002248 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002249 return(NULL);
2250 }
2251 if (nota->name != NULL)
2252 cur->name = xmlStrdup(nota->name);
2253 else
2254 cur->name = NULL;
2255 if (nota->PublicID != NULL)
2256 cur->PublicID = xmlStrdup(nota->PublicID);
2257 else
2258 cur->PublicID = NULL;
2259 if (nota->SystemID != NULL)
2260 cur->SystemID = xmlStrdup(nota->SystemID);
2261 else
2262 cur->SystemID = NULL;
2263 return(cur);
2264}
2265
2266/**
2267 * xmlCopyNotationTable:
2268 * @table: A notation table
2269 *
2270 * Build a copy of a notation table.
2271 *
2272 * Returns the new xmlNotationTablePtr or NULL in case of error.
2273 */
2274xmlNotationTablePtr
2275xmlCopyNotationTable(xmlNotationTablePtr table) {
2276 return((xmlNotationTablePtr) xmlHashCopy(table,
2277 (xmlHashCopier) xmlCopyNotation));
2278}
Daniel Veillard652327a2003-09-29 18:02:38 +00002279#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002280
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002281#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002282/**
2283 * xmlDumpNotationDecl:
2284 * @buf: the XML buffer output
2285 * @nota: A notation declaration
2286 *
2287 * This will dump the content the notation declaration as an XML DTD definition
2288 */
2289void
2290xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2291 xmlBufferWriteChar(buf, "<!NOTATION ");
2292 xmlBufferWriteCHAR(buf, nota->name);
2293 if (nota->PublicID != NULL) {
2294 xmlBufferWriteChar(buf, " PUBLIC ");
2295 xmlBufferWriteQuotedString(buf, nota->PublicID);
2296 if (nota->SystemID != NULL) {
2297 xmlBufferWriteChar(buf, " ");
2298 xmlBufferWriteCHAR(buf, nota->SystemID);
2299 }
2300 } else {
2301 xmlBufferWriteChar(buf, " SYSTEM ");
2302 xmlBufferWriteCHAR(buf, nota->SystemID);
2303 }
2304 xmlBufferWriteChar(buf, " >\n");
2305}
2306
2307/**
2308 * xmlDumpNotationTable:
2309 * @buf: the XML buffer output
2310 * @table: A notation table
2311 *
2312 * This will dump the content of the notation table as an XML DTD definition
2313 */
2314void
2315xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2316 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDecl, buf);
2317}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002318#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002319
2320/************************************************************************
2321 * *
2322 * IDs *
2323 * *
2324 ************************************************************************/
2325/**
2326 * xmlCreateIDTable:
2327 *
2328 * create and initialize an empty id hash table.
2329 *
2330 * Returns the xmlIDTablePtr just created or NULL in case
2331 * of error.
2332 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002333static xmlIDTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002334xmlCreateIDTable(void) {
2335 return(xmlHashCreate(0));
2336}
2337
2338/**
2339 * xmlFreeID:
2340 * @not: A id
2341 *
2342 * Deallocate the memory used by an id definition
2343 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002344static void
Owen Taylor3473f882001-02-23 17:55:21 +00002345xmlFreeID(xmlIDPtr id) {
2346 if (id == NULL) return;
2347 if (id->value != NULL)
2348 xmlFree((xmlChar *) id->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002349 if (id->name != NULL)
2350 xmlFree((xmlChar *) id->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002351 xmlFree(id);
2352}
2353
2354/**
2355 * xmlAddID:
2356 * @ctxt: the validation context
2357 * @doc: pointer to the document
2358 * @value: the value name
2359 * @attr: the attribute holding the ID
2360 *
2361 * Register a new id declaration
2362 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002363 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002364 */
2365xmlIDPtr
2366xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2367 xmlAttrPtr attr) {
2368 xmlIDPtr ret;
2369 xmlIDTablePtr table;
2370
2371 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002372 return(NULL);
2373 }
2374 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002375 return(NULL);
2376 }
2377 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002378 return(NULL);
2379 }
2380
2381 /*
2382 * Create the ID table if needed.
2383 */
2384 table = (xmlIDTablePtr) doc->ids;
2385 if (table == NULL)
2386 doc->ids = table = xmlCreateIDTable();
2387 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002388 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002389 "xmlAddID: Table creation failed!\n");
2390 return(NULL);
2391 }
2392
2393 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2394 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002395 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002396 return(NULL);
2397 }
2398
2399 /*
2400 * fill the structure.
2401 */
2402 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002403 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2404 /*
2405 * Operating in streaming mode, attr is gonna disapear
2406 */
2407 ret->name = xmlStrdup(attr->name);
2408 ret->attr = NULL;
2409 } else {
2410 ret->attr = attr;
2411 ret->name = NULL;
2412 }
2413 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002414
2415 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002416#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002417 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002418 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002419 */
Daniel Veillard76575762002-09-05 14:21:15 +00002420 if (ctxt != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002421 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2422 "ID %s already defined\n",
2423 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002424 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002425#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002426 xmlFreeID(ret);
2427 return(NULL);
2428 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002429 if (attr != NULL)
2430 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002431 return(ret);
2432}
2433
2434/**
2435 * xmlFreeIDTable:
2436 * @table: An id table
2437 *
2438 * Deallocate the memory used by an ID hash table.
2439 */
2440void
2441xmlFreeIDTable(xmlIDTablePtr table) {
2442 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2443}
2444
2445/**
2446 * xmlIsID:
2447 * @doc: the document
2448 * @elem: the element carrying the attribute
2449 * @attr: the attribute
2450 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002451 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002452 * then this is done if DTD loading has been requested. In the case
2453 * of HTML documents parsed with the HTML parser, then ID detection is
2454 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002455 *
2456 * Returns 0 or 1 depending on the lookup result
2457 */
2458int
2459xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2460 if (doc == NULL) return(0);
2461 if (attr == NULL) return(0);
2462 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2463 return(0);
2464 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2465 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2466 (xmlStrEqual(BAD_CAST "name", attr->name)))
2467 return(1);
2468 return(0);
2469 } else {
2470 xmlAttributePtr attrDecl;
2471
2472 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002473 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002474 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002475 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002476
2477 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002478 if (fullname == NULL)
2479 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002480 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2481 attr->name);
2482 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2483 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2484 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002485 if ((fullname != fn) && (fullname != elem->name))
2486 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002487 } else {
2488 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2489 attr->name);
2490 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2491 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2492 attr->name);
2493 }
Owen Taylor3473f882001-02-23 17:55:21 +00002494
2495 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2496 return(1);
2497 }
2498 return(0);
2499}
2500
2501/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002502 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002503 * @doc: the document
2504 * @attr: the attribute
2505 *
2506 * Remove the given attribute from the ID table maintained internally.
2507 *
2508 * Returns -1 if the lookup failed and 0 otherwise
2509 */
2510int
2511xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2512 xmlAttrPtr cur;
2513 xmlIDTablePtr table;
2514 xmlChar *ID;
2515
2516 if (doc == NULL) return(-1);
2517 if (attr == NULL) return(-1);
2518 table = (xmlIDTablePtr) doc->ids;
2519 if (table == NULL)
2520 return(-1);
2521
2522 if (attr == NULL)
2523 return(-1);
2524 ID = xmlNodeListGetString(doc, attr->children, 1);
2525 if (ID == NULL)
2526 return(-1);
2527 cur = xmlHashLookup(table, ID);
2528 if (cur != attr) {
2529 xmlFree(ID);
2530 return(-1);
2531 }
2532 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
2533 xmlFree(ID);
2534 return(0);
2535}
2536
2537/**
2538 * xmlGetID:
2539 * @doc: pointer to the document
2540 * @ID: the ID value
2541 *
2542 * Search the attribute declaring the given ID
2543 *
2544 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2545 */
2546xmlAttrPtr
2547xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2548 xmlIDTablePtr table;
2549 xmlIDPtr id;
2550
2551 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002552 return(NULL);
2553 }
2554
2555 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002556 return(NULL);
2557 }
2558
2559 table = (xmlIDTablePtr) doc->ids;
2560 if (table == NULL)
2561 return(NULL);
2562
2563 id = xmlHashLookup(table, ID);
2564 if (id == NULL)
2565 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002566 if (id->attr == NULL) {
2567 /*
2568 * We are operating on a stream, return a well known reference
2569 * since the attribute node doesn't exist anymore
2570 */
2571 return((xmlAttrPtr) doc);
2572 }
Owen Taylor3473f882001-02-23 17:55:21 +00002573 return(id->attr);
2574}
2575
2576/************************************************************************
2577 * *
2578 * Refs *
2579 * *
2580 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002581typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002582{
2583 xmlListPtr l;
2584 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002585} xmlRemoveMemo;
2586
2587typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2588
2589typedef struct xmlValidateMemo_t
2590{
2591 xmlValidCtxtPtr ctxt;
2592 const xmlChar *name;
2593} xmlValidateMemo;
2594
2595typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002596
2597/**
2598 * xmlCreateRefTable:
2599 *
2600 * create and initialize an empty ref hash table.
2601 *
2602 * Returns the xmlRefTablePtr just created or NULL in case
2603 * of error.
2604 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002605static xmlRefTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002606xmlCreateRefTable(void) {
2607 return(xmlHashCreate(0));
2608}
2609
2610/**
2611 * xmlFreeRef:
2612 * @lk: A list link
2613 *
2614 * Deallocate the memory used by a ref definition
2615 */
2616static void
2617xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002618 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2619 if (ref == NULL) return;
2620 if (ref->value != NULL)
2621 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002622 if (ref->name != NULL)
2623 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002624 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002625}
2626
2627/**
2628 * xmlFreeRefList:
2629 * @list_ref: A list of references.
2630 *
2631 * Deallocate the memory used by a list of references
2632 */
2633static void
2634xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002635 if (list_ref == NULL) return;
2636 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002637}
2638
2639/**
2640 * xmlWalkRemoveRef:
2641 * @data: Contents of current link
2642 * @user: Value supplied by the user
2643 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002644 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002645 */
2646static int
2647xmlWalkRemoveRef(const void *data, const void *user)
2648{
Daniel Veillard37721922001-05-04 15:21:12 +00002649 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2650 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2651 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002652
Daniel Veillard37721922001-05-04 15:21:12 +00002653 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2654 xmlListRemoveFirst(ref_list, (void *)data);
2655 return 0;
2656 }
2657 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002658}
2659
2660/**
2661 * xmlAddRef:
2662 * @ctxt: the validation context
2663 * @doc: pointer to the document
2664 * @value: the value name
2665 * @attr: the attribute holding the Ref
2666 *
2667 * Register a new ref declaration
2668 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002669 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002670 */
2671xmlRefPtr
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00002672xmlAddRef(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002673 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002674 xmlRefPtr ret;
2675 xmlRefTablePtr table;
2676 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002677
Daniel Veillard37721922001-05-04 15:21:12 +00002678 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002679 return(NULL);
2680 }
2681 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002682 return(NULL);
2683 }
2684 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002685 return(NULL);
2686 }
Owen Taylor3473f882001-02-23 17:55:21 +00002687
Daniel Veillard37721922001-05-04 15:21:12 +00002688 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002689 * Create the Ref table if needed.
2690 */
Daniel Veillard37721922001-05-04 15:21:12 +00002691 table = (xmlRefTablePtr) doc->refs;
2692 if (table == NULL)
2693 doc->refs = table = xmlCreateRefTable();
2694 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002695 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002696 "xmlAddRef: Table creation failed!\n");
2697 return(NULL);
2698 }
Owen Taylor3473f882001-02-23 17:55:21 +00002699
Daniel Veillard37721922001-05-04 15:21:12 +00002700 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2701 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002702 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002703 return(NULL);
2704 }
Owen Taylor3473f882001-02-23 17:55:21 +00002705
Daniel Veillard37721922001-05-04 15:21:12 +00002706 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002707 * fill the structure.
2708 */
Daniel Veillard37721922001-05-04 15:21:12 +00002709 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002710 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2711 /*
2712 * Operating in streaming mode, attr is gonna disapear
2713 */
2714 ret->name = xmlStrdup(attr->name);
2715 ret->attr = NULL;
2716 } else {
2717 ret->name = NULL;
2718 ret->attr = attr;
2719 }
2720 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002721
Daniel Veillard37721922001-05-04 15:21:12 +00002722 /* To add a reference :-
2723 * References are maintained as a list of references,
2724 * Lookup the entry, if no entry create new nodelist
2725 * Add the owning node to the NodeList
2726 * Return the ref
2727 */
Owen Taylor3473f882001-02-23 17:55:21 +00002728
Daniel Veillard37721922001-05-04 15:21:12 +00002729 if (NULL == (ref_list = xmlHashLookup(table, value))) {
2730 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, NULL))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002731 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2732 "xmlAddRef: Reference list creation failed!\n",
2733 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002734 return(NULL);
2735 }
2736 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2737 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002738 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2739 "xmlAddRef: Reference list insertion failed!\n",
2740 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002741 return(NULL);
2742 }
2743 }
2744 xmlListInsert(ref_list, ret);
2745 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002746}
2747
2748/**
2749 * xmlFreeRefTable:
2750 * @table: An ref table
2751 *
2752 * Deallocate the memory used by an Ref hash table.
2753 */
2754void
2755xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002756 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002757}
2758
2759/**
2760 * xmlIsRef:
2761 * @doc: the document
2762 * @elem: the element carrying the attribute
2763 * @attr: the attribute
2764 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002765 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00002766 * then this is simple, otherwise we use an heuristic: name Ref (upper
2767 * or lowercase).
2768 *
2769 * Returns 0 or 1 depending on the lookup result
2770 */
2771int
2772xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002773 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2774 return(0);
2775 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2776 /* TODO @@@ */
2777 return(0);
2778 } else {
2779 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00002780
Daniel Veillard37721922001-05-04 15:21:12 +00002781 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2782 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2783 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2784 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002785
Daniel Veillard37721922001-05-04 15:21:12 +00002786 if ((attrDecl != NULL) &&
2787 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2788 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2789 return(1);
2790 }
2791 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002792}
2793
2794/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002795 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00002796 * @doc: the document
2797 * @attr: the attribute
2798 *
2799 * Remove the given attribute from the Ref table maintained internally.
2800 *
2801 * Returns -1 if the lookup failed and 0 otherwise
2802 */
2803int
2804xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002805 xmlListPtr ref_list;
2806 xmlRefTablePtr table;
2807 xmlChar *ID;
2808 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00002809
Daniel Veillard37721922001-05-04 15:21:12 +00002810 if (doc == NULL) return(-1);
2811 if (attr == NULL) return(-1);
2812 table = (xmlRefTablePtr) doc->refs;
2813 if (table == NULL)
2814 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002815
Daniel Veillard37721922001-05-04 15:21:12 +00002816 if (attr == NULL)
2817 return(-1);
2818 ID = xmlNodeListGetString(doc, attr->children, 1);
2819 if (ID == NULL)
2820 return(-1);
2821 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00002822
Daniel Veillard37721922001-05-04 15:21:12 +00002823 if(ref_list == NULL) {
2824 xmlFree(ID);
2825 return (-1);
2826 }
2827 /* At this point, ref_list refers to a list of references which
2828 * have the same key as the supplied attr. Our list of references
2829 * is ordered by reference address and we don't have that information
2830 * here to use when removing. We'll have to walk the list and
2831 * check for a matching attribute, when we find one stop the walk
2832 * and remove the entry.
2833 * The list is ordered by reference, so that means we don't have the
2834 * key. Passing the list and the reference to the walker means we
2835 * will have enough data to be able to remove the entry.
2836 */
2837 target.l = ref_list;
2838 target.ap = attr;
2839
2840 /* Remove the supplied attr from our list */
2841 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00002842
Daniel Veillard37721922001-05-04 15:21:12 +00002843 /*If the list is empty then remove the list entry in the hash */
2844 if (xmlListEmpty(ref_list))
2845 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2846 xmlFreeRefList);
2847 xmlFree(ID);
2848 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002849}
2850
2851/**
2852 * xmlGetRefs:
2853 * @doc: pointer to the document
2854 * @ID: the ID value
2855 *
2856 * Find the set of references for the supplied ID.
2857 *
2858 * Returns NULL if not found, otherwise node set for the ID.
2859 */
2860xmlListPtr
2861xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00002862 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00002863
Daniel Veillard37721922001-05-04 15:21:12 +00002864 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002865 return(NULL);
2866 }
Owen Taylor3473f882001-02-23 17:55:21 +00002867
Daniel Veillard37721922001-05-04 15:21:12 +00002868 if (ID == 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 table = (xmlRefTablePtr) doc->refs;
2873 if (table == NULL)
2874 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002875
Daniel Veillard37721922001-05-04 15:21:12 +00002876 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00002877}
2878
2879/************************************************************************
2880 * *
2881 * Routines for validity checking *
2882 * *
2883 ************************************************************************/
2884
2885/**
2886 * xmlGetDtdElementDesc:
2887 * @dtd: a pointer to the DtD to search
2888 * @name: the element name
2889 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002890 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002891 *
2892 * returns the xmlElementPtr if found or NULL
2893 */
2894
2895xmlElementPtr
2896xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2897 xmlElementTablePtr table;
2898 xmlElementPtr cur;
2899 xmlChar *uqname = NULL, *prefix = NULL;
2900
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002901 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002902 if (dtd->elements == NULL)
2903 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002904 table = (xmlElementTablePtr) dtd->elements;
2905
2906 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002907 if (uqname != NULL)
2908 name = uqname;
2909 cur = xmlHashLookup2(table, name, prefix);
2910 if (prefix != NULL) xmlFree(prefix);
2911 if (uqname != NULL) xmlFree(uqname);
2912 return(cur);
2913}
2914/**
2915 * xmlGetDtdElementDesc2:
2916 * @dtd: a pointer to the DtD to search
2917 * @name: the element name
2918 * @create: create an empty description if not found
2919 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002920 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00002921 *
2922 * returns the xmlElementPtr if found or NULL
2923 */
2924
Daniel Veillard86fd5a72001-12-13 14:55:21 +00002925static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00002926xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
2927 xmlElementTablePtr table;
2928 xmlElementPtr cur;
2929 xmlChar *uqname = NULL, *prefix = NULL;
2930
2931 if (dtd == NULL) return(NULL);
2932 if (dtd->elements == NULL) {
2933 if (!create)
2934 return(NULL);
2935 /*
2936 * Create the Element table if needed.
2937 */
2938 table = (xmlElementTablePtr) dtd->elements;
2939 if (table == NULL) {
2940 table = xmlCreateElementTable();
2941 dtd->elements = (void *) table;
2942 }
2943 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002944 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00002945 return(NULL);
2946 }
2947 }
2948 table = (xmlElementTablePtr) dtd->elements;
2949
2950 uqname = xmlSplitQName2(name, &prefix);
2951 if (uqname != NULL)
2952 name = uqname;
2953 cur = xmlHashLookup2(table, name, prefix);
2954 if ((cur == NULL) && (create)) {
2955 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
2956 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002957 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00002958 return(NULL);
2959 }
2960 memset(cur, 0, sizeof(xmlElement));
2961 cur->type = XML_ELEMENT_DECL;
2962
2963 /*
2964 * fill the structure.
2965 */
2966 cur->name = xmlStrdup(name);
2967 cur->prefix = xmlStrdup(prefix);
2968 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
2969
2970 xmlHashAddEntry2(table, name, prefix, cur);
2971 }
2972 if (prefix != NULL) xmlFree(prefix);
2973 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00002974 return(cur);
2975}
2976
2977/**
2978 * xmlGetDtdQElementDesc:
2979 * @dtd: a pointer to the DtD to search
2980 * @name: the element name
2981 * @prefix: the element namespace prefix
2982 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002983 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002984 *
2985 * returns the xmlElementPtr if found or NULL
2986 */
2987
Daniel Veillard48da9102001-08-07 01:10:10 +00002988xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002989xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
2990 const xmlChar *prefix) {
2991 xmlElementTablePtr table;
2992
2993 if (dtd == NULL) return(NULL);
2994 if (dtd->elements == NULL) return(NULL);
2995 table = (xmlElementTablePtr) dtd->elements;
2996
2997 return(xmlHashLookup2(table, name, prefix));
2998}
2999
3000/**
3001 * xmlGetDtdAttrDesc:
3002 * @dtd: a pointer to the DtD to search
3003 * @elem: the element name
3004 * @name: the attribute name
3005 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003006 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003007 * this element.
3008 *
3009 * returns the xmlAttributePtr if found or NULL
3010 */
3011
3012xmlAttributePtr
3013xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3014 xmlAttributeTablePtr table;
3015 xmlAttributePtr cur;
3016 xmlChar *uqname = NULL, *prefix = NULL;
3017
3018 if (dtd == NULL) return(NULL);
3019 if (dtd->attributes == NULL) return(NULL);
3020
3021 table = (xmlAttributeTablePtr) dtd->attributes;
3022 if (table == NULL)
3023 return(NULL);
3024
3025 uqname = xmlSplitQName2(name, &prefix);
3026
3027 if (uqname != NULL) {
3028 cur = xmlHashLookup3(table, uqname, prefix, elem);
3029 if (prefix != NULL) xmlFree(prefix);
3030 if (uqname != NULL) xmlFree(uqname);
3031 } else
3032 cur = xmlHashLookup3(table, name, NULL, elem);
3033 return(cur);
3034}
3035
3036/**
3037 * xmlGetDtdQAttrDesc:
3038 * @dtd: a pointer to the DtD to search
3039 * @elem: the element name
3040 * @name: the attribute name
3041 * @prefix: the attribute namespace prefix
3042 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003043 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003044 * this element.
3045 *
3046 * returns the xmlAttributePtr if found or NULL
3047 */
3048
Daniel Veillard48da9102001-08-07 01:10:10 +00003049xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003050xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3051 const xmlChar *prefix) {
3052 xmlAttributeTablePtr table;
3053
3054 if (dtd == NULL) return(NULL);
3055 if (dtd->attributes == NULL) return(NULL);
3056 table = (xmlAttributeTablePtr) dtd->attributes;
3057
3058 return(xmlHashLookup3(table, name, prefix, elem));
3059}
3060
3061/**
3062 * xmlGetDtdNotationDesc:
3063 * @dtd: a pointer to the DtD to search
3064 * @name: the notation name
3065 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003066 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003067 *
3068 * returns the xmlNotationPtr if found or NULL
3069 */
3070
3071xmlNotationPtr
3072xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3073 xmlNotationTablePtr table;
3074
3075 if (dtd == NULL) return(NULL);
3076 if (dtd->notations == NULL) return(NULL);
3077 table = (xmlNotationTablePtr) dtd->notations;
3078
3079 return(xmlHashLookup(table, name));
3080}
3081
Daniel Veillard4432df22003-09-28 18:58:27 +00003082#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003083/**
3084 * xmlValidateNotationUse:
3085 * @ctxt: the validation context
3086 * @doc: the document
3087 * @notationName: the notation name to check
3088 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003089 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003090 * - [ VC: Notation Declared ]
3091 *
3092 * returns 1 if valid or 0 otherwise
3093 */
3094
3095int
3096xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3097 const xmlChar *notationName) {
3098 xmlNotationPtr notaDecl;
3099 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3100
3101 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3102 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3103 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3104
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003105 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003106 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3107 "NOTATION %s is not declared\n",
3108 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003109 return(0);
3110 }
3111 return(1);
3112}
Daniel Veillard4432df22003-09-28 18:58:27 +00003113#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003114
3115/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003116 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003117 * @doc: the document
3118 * @name: the element name
3119 *
3120 * Search in the DtDs whether an element accept Mixed content (or ANY)
3121 * basically if it is supposed to accept text childs
3122 *
3123 * returns 0 if no, 1 if yes, and -1 if no element description is available
3124 */
3125
3126int
3127xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3128 xmlElementPtr elemDecl;
3129
3130 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3131
3132 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3133 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3134 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3135 if (elemDecl == NULL) return(-1);
3136 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003137 case XML_ELEMENT_TYPE_UNDEFINED:
3138 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003139 case XML_ELEMENT_TYPE_ELEMENT:
3140 return(0);
3141 case XML_ELEMENT_TYPE_EMPTY:
3142 /*
3143 * return 1 for EMPTY since we want VC error to pop up
3144 * on <empty> </empty> for example
3145 */
3146 case XML_ELEMENT_TYPE_ANY:
3147 case XML_ELEMENT_TYPE_MIXED:
3148 return(1);
3149 }
3150 return(1);
3151}
3152
Daniel Veillard4432df22003-09-28 18:58:27 +00003153#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003154/**
3155 * xmlValidateNameValue:
3156 * @value: an Name value
3157 *
3158 * Validate that the given value match Name production
3159 *
3160 * returns 1 if valid or 0 otherwise
3161 */
3162
Daniel Veillard9b731d72002-04-14 12:56:08 +00003163int
Owen Taylor3473f882001-02-23 17:55:21 +00003164xmlValidateNameValue(const xmlChar *value) {
3165 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003166 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003167
3168 if (value == NULL) return(0);
3169 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003170 val = xmlStringCurrentChar(NULL, cur, &len);
3171 cur += len;
3172 if (!IS_LETTER(val) && (val != '_') &&
3173 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003174 return(0);
3175 }
3176
Daniel Veillardd8224e02002-01-13 15:43:22 +00003177 val = xmlStringCurrentChar(NULL, cur, &len);
3178 cur += len;
3179 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3180 (val == '.') || (val == '-') ||
3181 (val == '_') || (val == ':') ||
3182 (IS_COMBINING(val)) ||
3183 (IS_EXTENDER(val))) {
3184 val = xmlStringCurrentChar(NULL, cur, &len);
3185 cur += len;
3186 }
Owen Taylor3473f882001-02-23 17:55:21 +00003187
Daniel Veillardd8224e02002-01-13 15:43:22 +00003188 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003189
3190 return(1);
3191}
3192
3193/**
3194 * xmlValidateNamesValue:
3195 * @value: an Names value
3196 *
3197 * Validate that the given value match Names production
3198 *
3199 * returns 1 if valid or 0 otherwise
3200 */
3201
Daniel Veillard9b731d72002-04-14 12:56:08 +00003202int
Owen Taylor3473f882001-02-23 17:55:21 +00003203xmlValidateNamesValue(const xmlChar *value) {
3204 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003205 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003206
3207 if (value == NULL) return(0);
3208 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003209 val = xmlStringCurrentChar(NULL, cur, &len);
3210 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003211
Daniel Veillardd8224e02002-01-13 15:43:22 +00003212 if (!IS_LETTER(val) && (val != '_') &&
3213 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003214 return(0);
3215 }
3216
Daniel Veillardd8224e02002-01-13 15:43:22 +00003217 val = xmlStringCurrentChar(NULL, cur, &len);
3218 cur += len;
3219 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3220 (val == '.') || (val == '-') ||
3221 (val == '_') || (val == ':') ||
3222 (IS_COMBINING(val)) ||
3223 (IS_EXTENDER(val))) {
3224 val = xmlStringCurrentChar(NULL, cur, &len);
3225 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003226 }
3227
Daniel Veillardd8224e02002-01-13 15:43:22 +00003228 while (IS_BLANK(val)) {
3229 while (IS_BLANK(val)) {
3230 val = xmlStringCurrentChar(NULL, cur, &len);
3231 cur += len;
3232 }
3233
3234 if (!IS_LETTER(val) && (val != '_') &&
3235 (val != ':')) {
3236 return(0);
3237 }
3238 val = xmlStringCurrentChar(NULL, cur, &len);
3239 cur += len;
3240
3241 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3242 (val == '.') || (val == '-') ||
3243 (val == '_') || (val == ':') ||
3244 (IS_COMBINING(val)) ||
3245 (IS_EXTENDER(val))) {
3246 val = xmlStringCurrentChar(NULL, cur, &len);
3247 cur += len;
3248 }
3249 }
3250
3251 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003252
3253 return(1);
3254}
3255
3256/**
3257 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003258 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003259 *
3260 * Validate that the given value match Nmtoken production
3261 *
3262 * [ VC: Name Token ]
3263 *
3264 * returns 1 if valid or 0 otherwise
3265 */
3266
Daniel Veillard9b731d72002-04-14 12:56:08 +00003267int
Owen Taylor3473f882001-02-23 17:55:21 +00003268xmlValidateNmtokenValue(const xmlChar *value) {
3269 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003270 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003271
3272 if (value == NULL) return(0);
3273 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003274 val = xmlStringCurrentChar(NULL, cur, &len);
3275 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003276
Daniel Veillardd8224e02002-01-13 15:43:22 +00003277 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3278 (val != '.') && (val != '-') &&
3279 (val != '_') && (val != ':') &&
3280 (!IS_COMBINING(val)) &&
3281 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003282 return(0);
3283
Daniel Veillardd8224e02002-01-13 15:43:22 +00003284 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3285 (val == '.') || (val == '-') ||
3286 (val == '_') || (val == ':') ||
3287 (IS_COMBINING(val)) ||
3288 (IS_EXTENDER(val))) {
3289 val = xmlStringCurrentChar(NULL, cur, &len);
3290 cur += len;
3291 }
Owen Taylor3473f882001-02-23 17:55:21 +00003292
Daniel Veillardd8224e02002-01-13 15:43:22 +00003293 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003294
3295 return(1);
3296}
3297
3298/**
3299 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003300 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003301 *
3302 * Validate that the given value match Nmtokens production
3303 *
3304 * [ VC: Name Token ]
3305 *
3306 * returns 1 if valid or 0 otherwise
3307 */
3308
Daniel Veillard9b731d72002-04-14 12:56:08 +00003309int
Owen Taylor3473f882001-02-23 17:55:21 +00003310xmlValidateNmtokensValue(const xmlChar *value) {
3311 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003312 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003313
3314 if (value == NULL) return(0);
3315 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003316 val = xmlStringCurrentChar(NULL, cur, &len);
3317 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003318
Daniel Veillardd8224e02002-01-13 15:43:22 +00003319 while (IS_BLANK(val)) {
3320 val = xmlStringCurrentChar(NULL, cur, &len);
3321 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003322 }
3323
Daniel Veillardd8224e02002-01-13 15:43:22 +00003324 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3325 (val != '.') && (val != '-') &&
3326 (val != '_') && (val != ':') &&
3327 (!IS_COMBINING(val)) &&
3328 (!IS_EXTENDER(val)))
3329 return(0);
3330
3331 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3332 (val == '.') || (val == '-') ||
3333 (val == '_') || (val == ':') ||
3334 (IS_COMBINING(val)) ||
3335 (IS_EXTENDER(val))) {
3336 val = xmlStringCurrentChar(NULL, cur, &len);
3337 cur += len;
3338 }
3339
3340 while (IS_BLANK(val)) {
3341 while (IS_BLANK(val)) {
3342 val = xmlStringCurrentChar(NULL, cur, &len);
3343 cur += len;
3344 }
3345 if (val == 0) return(1);
3346
3347 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3348 (val != '.') && (val != '-') &&
3349 (val != '_') && (val != ':') &&
3350 (!IS_COMBINING(val)) &&
3351 (!IS_EXTENDER(val)))
3352 return(0);
3353
3354 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3355 (val == '.') || (val == '-') ||
3356 (val == '_') || (val == ':') ||
3357 (IS_COMBINING(val)) ||
3358 (IS_EXTENDER(val))) {
3359 val = xmlStringCurrentChar(NULL, cur, &len);
3360 cur += len;
3361 }
3362 }
3363
3364 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003365
3366 return(1);
3367}
3368
3369/**
3370 * xmlValidateNotationDecl:
3371 * @ctxt: the validation context
3372 * @doc: a document instance
3373 * @nota: a notation definition
3374 *
3375 * Try to validate a single notation definition
3376 * basically it does the following checks as described by the
3377 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003378 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003379 * But this function get called anyway ...
3380 *
3381 * returns 1 if valid or 0 otherwise
3382 */
3383
3384int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003385xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3386 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003387 int ret = 1;
3388
3389 return(ret);
3390}
3391
3392/**
3393 * xmlValidateAttributeValue:
3394 * @type: an attribute type
3395 * @value: an attribute value
3396 *
3397 * Validate that the given attribute value match the proper production
3398 *
3399 * [ VC: ID ]
3400 * Values of type ID must match the Name production....
3401 *
3402 * [ VC: IDREF ]
3403 * Values of type IDREF must match the Name production, and values
3404 * of type IDREFS must match Names ...
3405 *
3406 * [ VC: Entity Name ]
3407 * Values of type ENTITY must match the Name production, values
3408 * of type ENTITIES must match Names ...
3409 *
3410 * [ VC: Name Token ]
3411 * Values of type NMTOKEN must match the Nmtoken production; values
3412 * of type NMTOKENS must match Nmtokens.
3413 *
3414 * returns 1 if valid or 0 otherwise
3415 */
3416
3417int
3418xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3419 switch (type) {
3420 case XML_ATTRIBUTE_ENTITIES:
3421 case XML_ATTRIBUTE_IDREFS:
3422 return(xmlValidateNamesValue(value));
3423 case XML_ATTRIBUTE_ENTITY:
3424 case XML_ATTRIBUTE_IDREF:
3425 case XML_ATTRIBUTE_ID:
3426 case XML_ATTRIBUTE_NOTATION:
3427 return(xmlValidateNameValue(value));
3428 case XML_ATTRIBUTE_NMTOKENS:
3429 case XML_ATTRIBUTE_ENUMERATION:
3430 return(xmlValidateNmtokensValue(value));
3431 case XML_ATTRIBUTE_NMTOKEN:
3432 return(xmlValidateNmtokenValue(value));
3433 case XML_ATTRIBUTE_CDATA:
3434 break;
3435 }
3436 return(1);
3437}
3438
3439/**
3440 * xmlValidateAttributeValue2:
3441 * @ctxt: the validation context
3442 * @doc: the document
3443 * @name: the attribute name (used for error reporting only)
3444 * @type: the attribute type
3445 * @value: the attribute value
3446 *
3447 * Validate that the given attribute value match a given type.
3448 * This typically cannot be done before having finished parsing
3449 * the subsets.
3450 *
3451 * [ VC: IDREF ]
3452 * Values of type IDREF must match one of the declared IDs
3453 * Values of type IDREFS must match a sequence of the declared IDs
3454 * each Name must match the value of an ID attribute on some element
3455 * in the XML document; i.e. IDREF values must match the value of
3456 * some ID attribute
3457 *
3458 * [ VC: Entity Name ]
3459 * Values of type ENTITY must match one declared entity
3460 * Values of type ENTITIES must match a sequence of declared entities
3461 *
3462 * [ VC: Notation Attributes ]
3463 * all notation names in the declaration must be declared.
3464 *
3465 * returns 1 if valid or 0 otherwise
3466 */
3467
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003468static int
Owen Taylor3473f882001-02-23 17:55:21 +00003469xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3470 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3471 int ret = 1;
3472 switch (type) {
3473 case XML_ATTRIBUTE_IDREFS:
3474 case XML_ATTRIBUTE_IDREF:
3475 case XML_ATTRIBUTE_ID:
3476 case XML_ATTRIBUTE_NMTOKENS:
3477 case XML_ATTRIBUTE_ENUMERATION:
3478 case XML_ATTRIBUTE_NMTOKEN:
3479 case XML_ATTRIBUTE_CDATA:
3480 break;
3481 case XML_ATTRIBUTE_ENTITY: {
3482 xmlEntityPtr ent;
3483
3484 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003485 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003486 if ((ent == NULL) && (doc->standalone == 1)) {
3487 doc->standalone = 0;
3488 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003489 }
Owen Taylor3473f882001-02-23 17:55:21 +00003490 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003491 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3492 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003493 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003494 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003495 ret = 0;
3496 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003497 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3498 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003499 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003500 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003501 ret = 0;
3502 }
3503 break;
3504 }
3505 case XML_ATTRIBUTE_ENTITIES: {
3506 xmlChar *dup, *nam = NULL, *cur, save;
3507 xmlEntityPtr ent;
3508
3509 dup = xmlStrdup(value);
3510 if (dup == NULL)
3511 return(0);
3512 cur = dup;
3513 while (*cur != 0) {
3514 nam = cur;
3515 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3516 save = *cur;
3517 *cur = 0;
3518 ent = xmlGetDocEntity(doc, nam);
3519 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003520 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3521 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003522 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003523 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003524 ret = 0;
3525 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003526 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3527 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003528 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003529 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003530 ret = 0;
3531 }
3532 if (save == 0)
3533 break;
3534 *cur = save;
3535 while (IS_BLANK(*cur)) cur++;
3536 }
3537 xmlFree(dup);
3538 break;
3539 }
3540 case XML_ATTRIBUTE_NOTATION: {
3541 xmlNotationPtr nota;
3542
3543 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3544 if ((nota == NULL) && (doc->extSubset != NULL))
3545 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3546
3547 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003548 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3549 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003550 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003551 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003552 ret = 0;
3553 }
3554 break;
3555 }
3556 }
3557 return(ret);
3558}
3559
3560/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003561 * xmlValidCtxtNormalizeAttributeValue:
3562 * @ctxt: the validation context
3563 * @doc: the document
3564 * @elem: the parent
3565 * @name: the attribute name
3566 * @value: the attribute value
3567 * @ctxt: the validation context or NULL
3568 *
3569 * Does the validation related extra step of the normalization of attribute
3570 * values:
3571 *
3572 * If the declared value is not CDATA, then the XML processor must further
3573 * process the normalized attribute value by discarding any leading and
3574 * trailing space (#x20) characters, and by replacing sequences of space
3575 * (#x20) characters by single space (#x20) character.
3576 *
3577 * Also check VC: Standalone Document Declaration in P32, and update
3578 * ctxt->valid accordingly
3579 *
3580 * returns a new normalized string if normalization is needed, NULL otherwise
3581 * the caller must free the returned value.
3582 */
3583
3584xmlChar *
3585xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3586 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3587 xmlChar *ret, *dst;
3588 const xmlChar *src;
3589 xmlAttributePtr attrDecl = NULL;
3590 int extsubset = 0;
3591
3592 if (doc == NULL) return(NULL);
3593 if (elem == NULL) return(NULL);
3594 if (name == NULL) return(NULL);
3595 if (value == NULL) return(NULL);
3596
3597 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003598 xmlChar fn[50];
3599 xmlChar *fullname;
3600
3601 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3602 if (fullname == NULL)
3603 return(0);
3604 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003605 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003606 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003607 if (attrDecl != NULL)
3608 extsubset = 1;
3609 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003610 if ((fullname != fn) && (fullname != elem->name))
3611 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003612 }
3613 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3614 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3615 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3616 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3617 if (attrDecl != NULL)
3618 extsubset = 1;
3619 }
3620
3621 if (attrDecl == NULL)
3622 return(NULL);
3623 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3624 return(NULL);
3625
3626 ret = xmlStrdup(value);
3627 if (ret == NULL)
3628 return(NULL);
3629 src = value;
3630 dst = ret;
3631 while (*src == 0x20) src++;
3632 while (*src != 0) {
3633 if (*src == 0x20) {
3634 while (*src == 0x20) src++;
3635 if (*src != 0)
3636 *dst++ = 0x20;
3637 } else {
3638 *dst++ = *src++;
3639 }
3640 }
3641 *dst = 0;
3642 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003643 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003644"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003645 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003646 ctxt->valid = 0;
3647 }
3648 return(ret);
3649}
3650
3651/**
Owen Taylor3473f882001-02-23 17:55:21 +00003652 * xmlValidNormalizeAttributeValue:
3653 * @doc: the document
3654 * @elem: the parent
3655 * @name: the attribute name
3656 * @value: the attribute value
3657 *
3658 * Does the validation related extra step of the normalization of attribute
3659 * values:
3660 *
3661 * If the declared value is not CDATA, then the XML processor must further
3662 * process the normalized attribute value by discarding any leading and
3663 * trailing space (#x20) characters, and by replacing sequences of space
3664 * (#x20) characters by single space (#x20) character.
3665 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003666 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003667 * the caller must free the returned value.
3668 */
3669
3670xmlChar *
3671xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3672 const xmlChar *name, const xmlChar *value) {
3673 xmlChar *ret, *dst;
3674 const xmlChar *src;
3675 xmlAttributePtr attrDecl = NULL;
3676
3677 if (doc == NULL) return(NULL);
3678 if (elem == NULL) return(NULL);
3679 if (name == NULL) return(NULL);
3680 if (value == NULL) return(NULL);
3681
3682 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003683 xmlChar fn[50];
3684 xmlChar *fullname;
3685
3686 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3687 if (fullname == NULL)
3688 return(0);
3689 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003690 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003691 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3692 if ((fullname != fn) && (fullname != elem->name))
3693 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003694 }
3695 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3696 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3697 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3698
3699 if (attrDecl == NULL)
3700 return(NULL);
3701 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3702 return(NULL);
3703
3704 ret = xmlStrdup(value);
3705 if (ret == NULL)
3706 return(NULL);
3707 src = value;
3708 dst = ret;
3709 while (*src == 0x20) src++;
3710 while (*src != 0) {
3711 if (*src == 0x20) {
3712 while (*src == 0x20) src++;
3713 if (*src != 0)
3714 *dst++ = 0x20;
3715 } else {
3716 *dst++ = *src++;
3717 }
3718 }
3719 *dst = 0;
3720 return(ret);
3721}
3722
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003723static void
Owen Taylor3473f882001-02-23 17:55:21 +00003724xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003725 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003726 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3727}
3728
3729/**
3730 * xmlValidateAttributeDecl:
3731 * @ctxt: the validation context
3732 * @doc: a document instance
3733 * @attr: an attribute definition
3734 *
3735 * Try to validate a single attribute definition
3736 * basically it does the following checks as described by the
3737 * XML-1.0 recommendation:
3738 * - [ VC: Attribute Default Legal ]
3739 * - [ VC: Enumeration ]
3740 * - [ VC: ID Attribute Default ]
3741 *
3742 * The ID/IDREF uniqueness and matching are done separately
3743 *
3744 * returns 1 if valid or 0 otherwise
3745 */
3746
3747int
3748xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3749 xmlAttributePtr attr) {
3750 int ret = 1;
3751 int val;
3752 CHECK_DTD;
3753 if(attr == NULL) return(1);
3754
3755 /* Attribute Default Legal */
3756 /* Enumeration */
3757 if (attr->defaultValue != NULL) {
3758 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3759 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003760 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003761 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003762 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003763 }
3764 ret &= val;
3765 }
3766
3767 /* ID Attribute Default */
3768 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3769 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3770 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003771 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003772 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003773 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003774 ret = 0;
3775 }
3776
3777 /* One ID per Element Type */
3778 if (attr->atype == XML_ATTRIBUTE_ID) {
3779 int nbId;
3780
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003781 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00003782 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3783 attr->elem);
3784 if (elem != NULL) {
3785 nbId = xmlScanIDAttributeDecl(NULL, elem);
3786 } else {
3787 xmlAttributeTablePtr table;
3788
3789 /*
3790 * The attribute may be declared in the internal subset and the
3791 * element in the external subset.
3792 */
3793 nbId = 0;
3794 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3795 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3796 xmlValidateAttributeIdCallback, &nbId);
3797 }
3798 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003799
3800 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003801 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3802 attr->elem, nbId, attr->name);
3803 } else if (doc->extSubset != NULL) {
3804 int extId = 0;
3805 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3806 if (elem != NULL) {
3807 extId = xmlScanIDAttributeDecl(NULL, elem);
3808 }
3809 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003810 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003811 "Element %s has %d ID attribute defined in the external subset : %s\n",
3812 attr->elem, extId, attr->name);
3813 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003814 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003815"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003816 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003817 }
3818 }
3819 }
3820
3821 /* Validity Constraint: Enumeration */
3822 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3823 xmlEnumerationPtr tree = attr->tree;
3824 while (tree != NULL) {
3825 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3826 tree = tree->next;
3827 }
3828 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003829 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003830"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003831 attr->defaultValue, attr->name, attr->elem);
3832 ret = 0;
3833 }
3834 }
3835
3836 return(ret);
3837}
3838
3839/**
3840 * xmlValidateElementDecl:
3841 * @ctxt: the validation context
3842 * @doc: a document instance
3843 * @elem: an element definition
3844 *
3845 * Try to validate a single element definition
3846 * basically it does the following checks as described by the
3847 * XML-1.0 recommendation:
3848 * - [ VC: One ID per Element Type ]
3849 * - [ VC: No Duplicate Types ]
3850 * - [ VC: Unique Element Type Declaration ]
3851 *
3852 * returns 1 if valid or 0 otherwise
3853 */
3854
3855int
3856xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3857 xmlElementPtr elem) {
3858 int ret = 1;
3859 xmlElementPtr tst;
3860
3861 CHECK_DTD;
3862
3863 if (elem == NULL) return(1);
3864
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003865#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00003866#ifdef LIBXML_REGEXP_ENABLED
3867 /* Build the regexp associated to the content model */
3868 ret = xmlValidBuildContentModel(ctxt, elem);
3869#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003870#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00003871
Owen Taylor3473f882001-02-23 17:55:21 +00003872 /* No Duplicate Types */
3873 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3874 xmlElementContentPtr cur, next;
3875 const xmlChar *name;
3876
3877 cur = elem->content;
3878 while (cur != NULL) {
3879 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3880 if (cur->c1 == NULL) break;
3881 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3882 name = cur->c1->name;
3883 next = cur->c2;
3884 while (next != NULL) {
3885 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00003886 if ((xmlStrEqual(next->name, name)) &&
3887 (xmlStrEqual(next->prefix, cur->prefix))) {
3888 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003889 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00003890 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003891 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003892 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003893 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003894 "Definition of %s has duplicate references of %s:%s\n",
3895 elem->name, cur->prefix, name);
3896 }
Owen Taylor3473f882001-02-23 17:55:21 +00003897 ret = 0;
3898 }
3899 break;
3900 }
3901 if (next->c1 == NULL) break;
3902 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00003903 if ((xmlStrEqual(next->c1->name, name)) &&
3904 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
3905 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003906 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003907 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003908 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003909 } else {
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:%s\n",
3912 elem->name, cur->prefix, name);
3913 }
Owen Taylor3473f882001-02-23 17:55:21 +00003914 ret = 0;
3915 }
3916 next = next->c2;
3917 }
3918 }
3919 cur = cur->c2;
3920 }
3921 }
3922
3923 /* VC: Unique Element Type Declaration */
3924 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003925 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00003926 ((tst->prefix == elem->prefix) ||
3927 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00003928 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003929 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
3930 "Redefinition of element %s\n",
3931 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003932 ret = 0;
3933 }
3934 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003935 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00003936 ((tst->prefix == elem->prefix) ||
3937 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00003938 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003939 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
3940 "Redefinition of element %s\n",
3941 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003942 ret = 0;
3943 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00003944 /* One ID per Element Type
3945 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00003946 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3947 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00003948 } */
Owen Taylor3473f882001-02-23 17:55:21 +00003949 return(ret);
3950}
3951
3952/**
3953 * xmlValidateOneAttribute:
3954 * @ctxt: the validation context
3955 * @doc: a document instance
3956 * @elem: an element instance
3957 * @attr: an attribute instance
3958 * @value: the attribute value (without entities processing)
3959 *
3960 * Try to validate a single attribute for an element
3961 * basically it does the following checks as described by the
3962 * XML-1.0 recommendation:
3963 * - [ VC: Attribute Value Type ]
3964 * - [ VC: Fixed Attribute Default ]
3965 * - [ VC: Entity Name ]
3966 * - [ VC: Name Token ]
3967 * - [ VC: ID ]
3968 * - [ VC: IDREF ]
3969 * - [ VC: Entity Name ]
3970 * - [ VC: Notation Attributes ]
3971 *
3972 * The ID/IDREF uniqueness and matching are done separately
3973 *
3974 * returns 1 if valid or 0 otherwise
3975 */
3976
3977int
3978xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00003979 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
3980{
Owen Taylor3473f882001-02-23 17:55:21 +00003981 xmlAttributePtr attrDecl = NULL;
3982 int val;
3983 int ret = 1;
3984
3985 CHECK_DTD;
3986 if ((elem == NULL) || (elem->name == NULL)) return(0);
3987 if ((attr == NULL) || (attr->name == NULL)) return(0);
3988
3989 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003990 xmlChar fn[50];
3991 xmlChar *fullname;
3992
3993 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3994 if (fullname == NULL)
3995 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003996 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003997 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00003998 attr->name, attr->ns->prefix);
3999 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004000 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004001 attr->name, attr->ns->prefix);
4002 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004003 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004004 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4005 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004006 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004007 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004008 if ((fullname != fn) && (fullname != elem->name))
4009 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004010 }
4011 if (attrDecl == NULL) {
4012 if (attr->ns != NULL) {
4013 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4014 attr->name, attr->ns->prefix);
4015 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4016 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4017 attr->name, attr->ns->prefix);
4018 } else {
4019 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4020 elem->name, attr->name);
4021 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4022 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4023 elem->name, attr->name);
4024 }
4025 }
4026
4027
4028 /* Validity Constraint: Attribute Value Type */
4029 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004030 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004031 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004032 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004033 return(0);
4034 }
4035 attr->atype = attrDecl->atype;
4036
4037 val = xmlValidateAttributeValue(attrDecl->atype, value);
4038 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004039 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004040 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004041 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004042 ret = 0;
4043 }
4044
4045 /* Validity constraint: Fixed Attribute Default */
4046 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4047 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004048 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004049 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004050 attr->name, elem->name, attrDecl->defaultValue);
4051 ret = 0;
4052 }
4053 }
4054
4055 /* Validity Constraint: ID uniqueness */
4056 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4057 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4058 ret = 0;
4059 }
4060
4061 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4062 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4063 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4064 ret = 0;
4065 }
4066
4067 /* Validity Constraint: Notation Attributes */
4068 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4069 xmlEnumerationPtr tree = attrDecl->tree;
4070 xmlNotationPtr nota;
4071
4072 /* First check that the given NOTATION was declared */
4073 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4074 if (nota == NULL)
4075 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4076
4077 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004078 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004079 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004080 value, attr->name, elem->name);
4081 ret = 0;
4082 }
4083
4084 /* Second, verify that it's among the list */
4085 while (tree != NULL) {
4086 if (xmlStrEqual(tree->name, value)) break;
4087 tree = tree->next;
4088 }
4089 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004090 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004091"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004092 value, attr->name, elem->name);
4093 ret = 0;
4094 }
4095 }
4096
4097 /* Validity Constraint: Enumeration */
4098 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4099 xmlEnumerationPtr tree = attrDecl->tree;
4100 while (tree != NULL) {
4101 if (xmlStrEqual(tree->name, value)) break;
4102 tree = tree->next;
4103 }
4104 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004105 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004106 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004107 value, attr->name, elem->name);
4108 ret = 0;
4109 }
4110 }
4111
4112 /* Fixed Attribute Default */
4113 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4114 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004115 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004116 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004117 attr->name, elem->name, attrDecl->defaultValue);
4118 ret = 0;
4119 }
4120
4121 /* Extra check for the attribute value */
4122 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4123 attrDecl->atype, value);
4124
4125 return(ret);
4126}
4127
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004128/**
4129 * xmlValidateOneNamespace:
4130 * @ctxt: the validation context
4131 * @doc: a document instance
4132 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004133 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004134 * @ns: an namespace declaration instance
4135 * @value: the attribute value (without entities processing)
4136 *
4137 * Try to validate a single namespace declaration for an element
4138 * basically it does the following checks as described by the
4139 * XML-1.0 recommendation:
4140 * - [ VC: Attribute Value Type ]
4141 * - [ VC: Fixed Attribute Default ]
4142 * - [ VC: Entity Name ]
4143 * - [ VC: Name Token ]
4144 * - [ VC: ID ]
4145 * - [ VC: IDREF ]
4146 * - [ VC: Entity Name ]
4147 * - [ VC: Notation Attributes ]
4148 *
4149 * The ID/IDREF uniqueness and matching are done separately
4150 *
4151 * returns 1 if valid or 0 otherwise
4152 */
4153
4154int
4155xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4156xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4157 /* xmlElementPtr elemDecl; */
4158 xmlAttributePtr attrDecl = NULL;
4159 int val;
4160 int ret = 1;
4161
4162 CHECK_DTD;
4163 if ((elem == NULL) || (elem->name == NULL)) return(0);
4164 if ((ns == NULL) || (ns->href == NULL)) return(0);
4165
4166 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004167 xmlChar fn[50];
4168 xmlChar *fullname;
4169
4170 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4171 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004172 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004173 return(0);
4174 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004175 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004176 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004177 ns->prefix, BAD_CAST "xmlns");
4178 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004179 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004180 ns->prefix, BAD_CAST "xmlns");
4181 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004182 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004183 BAD_CAST "xmlns");
4184 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004185 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004186 BAD_CAST "xmlns");
4187 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004188 if ((fullname != fn) && (fullname != elem->name))
4189 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004190 }
4191 if (attrDecl == NULL) {
4192 if (ns->prefix != NULL) {
4193 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4194 ns->prefix, BAD_CAST "xmlns");
4195 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4196 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4197 ns->prefix, BAD_CAST "xmlns");
4198 } else {
4199 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4200 elem->name, BAD_CAST "xmlns");
4201 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4202 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4203 elem->name, BAD_CAST "xmlns");
4204 }
4205 }
4206
4207
4208 /* Validity Constraint: Attribute Value Type */
4209 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004210 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004211 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004212 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004213 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004214 } else {
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 of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004217 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004218 }
4219 return(0);
4220 }
4221
4222 val = xmlValidateAttributeValue(attrDecl->atype, value);
4223 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004224 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004225 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004226 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004227 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004228 } else {
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 of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004231 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004232 }
4233 ret = 0;
4234 }
4235
4236 /* Validity constraint: Fixed Attribute Default */
4237 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4238 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004239 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004240 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004241 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4242 ns->prefix, elem->name, attrDecl->defaultValue);
4243 } else {
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 of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004246 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004247 }
4248 ret = 0;
4249 }
4250 }
4251
4252 /* Validity Constraint: ID uniqueness */
4253 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4254 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4255 ret = 0;
4256 }
4257
4258 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4259 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4260 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4261 ret = 0;
4262 }
4263
4264 /* Validity Constraint: Notation Attributes */
4265 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4266 xmlEnumerationPtr tree = attrDecl->tree;
4267 xmlNotationPtr nota;
4268
4269 /* First check that the given NOTATION was declared */
4270 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4271 if (nota == NULL)
4272 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4273
4274 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004275 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004276 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004277 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4278 value, ns->prefix, elem->name);
4279 } else {
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 of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004282 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004283 }
4284 ret = 0;
4285 }
4286
4287 /* Second, verify that it's among the list */
4288 while (tree != NULL) {
4289 if (xmlStrEqual(tree->name, value)) break;
4290 tree = tree->next;
4291 }
4292 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004293 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004294 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004295"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4296 value, ns->prefix, elem->name);
4297 } else {
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 of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004300 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004301 }
4302 ret = 0;
4303 }
4304 }
4305
4306 /* Validity Constraint: Enumeration */
4307 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4308 xmlEnumerationPtr tree = attrDecl->tree;
4309 while (tree != NULL) {
4310 if (xmlStrEqual(tree->name, value)) break;
4311 tree = tree->next;
4312 }
4313 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004314 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004315 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004316"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4317 value, ns->prefix, elem->name);
4318 } else {
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 of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004321 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004322 }
4323 ret = 0;
4324 }
4325 }
4326
4327 /* Fixed Attribute Default */
4328 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4329 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004330 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004331 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004332 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4333 ns->prefix, elem->name, attrDecl->defaultValue);
4334 } else {
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 of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004337 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004338 }
4339 ret = 0;
4340 }
4341
4342 /* Extra check for the attribute value */
4343 if (ns->prefix != NULL) {
4344 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4345 attrDecl->atype, value);
4346 } else {
4347 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4348 attrDecl->atype, value);
4349 }
4350
4351 return(ret);
4352}
4353
Daniel Veillard118aed72002-09-24 14:13:13 +00004354#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004355/**
4356 * xmlValidateSkipIgnorable:
4357 * @ctxt: the validation context
4358 * @child: the child list
4359 *
4360 * Skip ignorable elements w.r.t. the validation process
4361 *
4362 * returns the first element to consider for validation of the content model
4363 */
4364
4365static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004366xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004367 while (child != NULL) {
4368 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004369 /* These things are ignored (skipped) during validation. */
4370 case XML_PI_NODE:
4371 case XML_COMMENT_NODE:
4372 case XML_XINCLUDE_START:
4373 case XML_XINCLUDE_END:
4374 child = child->next;
4375 break;
4376 case XML_TEXT_NODE:
4377 if (xmlIsBlankNode(child))
4378 child = child->next;
4379 else
4380 return(child);
4381 break;
4382 /* keep current node */
4383 default:
4384 return(child);
4385 }
4386 }
4387 return(child);
4388}
4389
4390/**
4391 * xmlValidateElementType:
4392 * @ctxt: the validation context
4393 *
4394 * Try to validate the content model of an element internal function
4395 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004396 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4397 * reference is found and -3 if the validation succeeded but
4398 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004399 */
4400
4401static int
4402xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004403 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004404 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004405
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004406 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004407 if ((NODE == NULL) && (CONT == NULL))
4408 return(1);
4409 if ((NODE == NULL) &&
4410 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4411 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4412 return(1);
4413 }
4414 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004415 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004416 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004417
4418 /*
4419 * We arrive here when more states need to be examined
4420 */
4421cont:
4422
4423 /*
4424 * We just recovered from a rollback generated by a possible
4425 * epsilon transition, go directly to the analysis phase
4426 */
4427 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004428 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004429 DEBUG_VALID_STATE(NODE, CONT)
4430 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004431 goto analyze;
4432 }
4433
4434 DEBUG_VALID_STATE(NODE, CONT)
4435 /*
4436 * we may have to save a backup state here. This is the equivalent
4437 * of handling epsilon transition in NFAs.
4438 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004439 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004440 ((CONT->parent == NULL) ||
4441 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004442 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004443 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004444 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004445 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004446 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4447 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004448 }
4449
4450
4451 /*
4452 * Check first if the content matches
4453 */
4454 switch (CONT->type) {
4455 case XML_ELEMENT_CONTENT_PCDATA:
4456 if (NODE == NULL) {
4457 DEBUG_VALID_MSG("pcdata failed no node");
4458 ret = 0;
4459 break;
4460 }
4461 if (NODE->type == XML_TEXT_NODE) {
4462 DEBUG_VALID_MSG("pcdata found, skip to next");
4463 /*
4464 * go to next element in the content model
4465 * skipping ignorable elems
4466 */
4467 do {
4468 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004469 NODE = xmlValidateSkipIgnorable(NODE);
4470 if ((NODE != NULL) &&
4471 (NODE->type == XML_ENTITY_REF_NODE))
4472 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004473 } while ((NODE != NULL) &&
4474 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004475 (NODE->type != XML_TEXT_NODE) &&
4476 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004477 ret = 1;
4478 break;
4479 } else {
4480 DEBUG_VALID_MSG("pcdata failed");
4481 ret = 0;
4482 break;
4483 }
4484 break;
4485 case XML_ELEMENT_CONTENT_ELEMENT:
4486 if (NODE == NULL) {
4487 DEBUG_VALID_MSG("element failed no node");
4488 ret = 0;
4489 break;
4490 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004491 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4492 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004493 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004494 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4495 ret = (CONT->prefix == NULL);
4496 } else if (CONT->prefix == NULL) {
4497 ret = 0;
4498 } else {
4499 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4500 }
4501 }
4502 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004503 DEBUG_VALID_MSG("element found, skip to next");
4504 /*
4505 * go to next element in the content model
4506 * skipping ignorable elems
4507 */
4508 do {
4509 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004510 NODE = xmlValidateSkipIgnorable(NODE);
4511 if ((NODE != NULL) &&
4512 (NODE->type == XML_ENTITY_REF_NODE))
4513 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004514 } while ((NODE != NULL) &&
4515 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004516 (NODE->type != XML_TEXT_NODE) &&
4517 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004518 } else {
4519 DEBUG_VALID_MSG("element failed");
4520 ret = 0;
4521 break;
4522 }
4523 break;
4524 case XML_ELEMENT_CONTENT_OR:
4525 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004526 * Small optimization.
4527 */
4528 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4529 if ((NODE == NULL) ||
4530 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4531 DEPTH++;
4532 CONT = CONT->c2;
4533 goto cont;
4534 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004535 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4536 ret = (CONT->c1->prefix == NULL);
4537 } else if (CONT->c1->prefix == NULL) {
4538 ret = 0;
4539 } else {
4540 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4541 }
4542 if (ret == 0) {
4543 DEPTH++;
4544 CONT = CONT->c2;
4545 goto cont;
4546 }
Daniel Veillard85349052001-04-20 13:48:21 +00004547 }
4548
4549 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004550 * save the second branch 'or' branch
4551 */
4552 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004553 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4554 OCCURS, ROLLBACK_OR) < 0)
4555 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004556 DEPTH++;
4557 CONT = CONT->c1;
4558 goto cont;
4559 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004560 /*
4561 * Small optimization.
4562 */
4563 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4564 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4565 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4566 if ((NODE == NULL) ||
4567 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4568 DEPTH++;
4569 CONT = CONT->c2;
4570 goto cont;
4571 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004572 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4573 ret = (CONT->c1->prefix == NULL);
4574 } else if (CONT->c1->prefix == NULL) {
4575 ret = 0;
4576 } else {
4577 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4578 }
4579 if (ret == 0) {
4580 DEPTH++;
4581 CONT = CONT->c2;
4582 goto cont;
4583 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004584 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004585 DEPTH++;
4586 CONT = CONT->c1;
4587 goto cont;
4588 }
4589
4590 /*
4591 * At this point handle going up in the tree
4592 */
4593 if (ret == -1) {
4594 DEBUG_VALID_MSG("error found returning");
4595 return(ret);
4596 }
4597analyze:
4598 while (CONT != NULL) {
4599 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004600 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004601 * this level.
4602 */
4603 if (ret == 0) {
4604 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004605 xmlNodePtr cur;
4606
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004607 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004608 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004609 DEBUG_VALID_MSG("Once branch failed, rollback");
4610 if (vstateVPop(ctxt) < 0 ) {
4611 DEBUG_VALID_MSG("exhaustion, failed");
4612 return(0);
4613 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004614 if (cur != ctxt->vstate->node)
4615 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004616 goto cont;
4617 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004618 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004619 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004620 DEBUG_VALID_MSG("Plus branch failed, rollback");
4621 if (vstateVPop(ctxt) < 0 ) {
4622 DEBUG_VALID_MSG("exhaustion, failed");
4623 return(0);
4624 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004625 if (cur != ctxt->vstate->node)
4626 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004627 goto cont;
4628 }
4629 DEBUG_VALID_MSG("Plus branch found");
4630 ret = 1;
4631 break;
4632 case XML_ELEMENT_CONTENT_MULT:
4633#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004634 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004635 DEBUG_VALID_MSG("Mult branch failed");
4636 } else {
4637 DEBUG_VALID_MSG("Mult branch found");
4638 }
4639#endif
4640 ret = 1;
4641 break;
4642 case XML_ELEMENT_CONTENT_OPT:
4643 DEBUG_VALID_MSG("Option branch failed");
4644 ret = 1;
4645 break;
4646 }
4647 } else {
4648 switch (CONT->ocur) {
4649 case XML_ELEMENT_CONTENT_OPT:
4650 DEBUG_VALID_MSG("Option branch succeeded");
4651 ret = 1;
4652 break;
4653 case XML_ELEMENT_CONTENT_ONCE:
4654 DEBUG_VALID_MSG("Once branch succeeded");
4655 ret = 1;
4656 break;
4657 case XML_ELEMENT_CONTENT_PLUS:
4658 if (STATE == ROLLBACK_PARENT) {
4659 DEBUG_VALID_MSG("Plus branch rollback");
4660 ret = 1;
4661 break;
4662 }
4663 if (NODE == NULL) {
4664 DEBUG_VALID_MSG("Plus branch exhausted");
4665 ret = 1;
4666 break;
4667 }
4668 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004669 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004670 goto cont;
4671 case XML_ELEMENT_CONTENT_MULT:
4672 if (STATE == ROLLBACK_PARENT) {
4673 DEBUG_VALID_MSG("Mult branch rollback");
4674 ret = 1;
4675 break;
4676 }
4677 if (NODE == NULL) {
4678 DEBUG_VALID_MSG("Mult branch exhausted");
4679 ret = 1;
4680 break;
4681 }
4682 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004683 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004684 goto cont;
4685 }
4686 }
4687 STATE = 0;
4688
4689 /*
4690 * Then act accordingly at the parent level
4691 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004692 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004693 if (CONT->parent == NULL)
4694 break;
4695
4696 switch (CONT->parent->type) {
4697 case XML_ELEMENT_CONTENT_PCDATA:
4698 DEBUG_VALID_MSG("Error: parent pcdata");
4699 return(-1);
4700 case XML_ELEMENT_CONTENT_ELEMENT:
4701 DEBUG_VALID_MSG("Error: parent element");
4702 return(-1);
4703 case XML_ELEMENT_CONTENT_OR:
4704 if (ret == 1) {
4705 DEBUG_VALID_MSG("Or succeeded");
4706 CONT = CONT->parent;
4707 DEPTH--;
4708 } else {
4709 DEBUG_VALID_MSG("Or failed");
4710 CONT = CONT->parent;
4711 DEPTH--;
4712 }
4713 break;
4714 case XML_ELEMENT_CONTENT_SEQ:
4715 if (ret == 0) {
4716 DEBUG_VALID_MSG("Sequence failed");
4717 CONT = CONT->parent;
4718 DEPTH--;
4719 } else if (CONT == CONT->parent->c1) {
4720 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4721 CONT = CONT->parent->c2;
4722 goto cont;
4723 } else {
4724 DEBUG_VALID_MSG("Sequence succeeded");
4725 CONT = CONT->parent;
4726 DEPTH--;
4727 }
4728 }
4729 }
4730 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004731 xmlNodePtr cur;
4732
4733 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004734 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4735 if (vstateVPop(ctxt) < 0 ) {
4736 DEBUG_VALID_MSG("exhaustion, failed");
4737 return(0);
4738 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004739 if (cur != ctxt->vstate->node)
4740 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004741 goto cont;
4742 }
4743 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004744 xmlNodePtr cur;
4745
4746 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004747 DEBUG_VALID_MSG("Failure, rollback");
4748 if (vstateVPop(ctxt) < 0 ) {
4749 DEBUG_VALID_MSG("exhaustion, failed");
4750 return(0);
4751 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004752 if (cur != ctxt->vstate->node)
4753 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004754 goto cont;
4755 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004756 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004757}
Daniel Veillard23e73572002-09-19 19:56:43 +00004758#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004759
4760/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00004761 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004762 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00004763 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004764 * @content: An element
4765 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4766 *
4767 * This will dump the list of elements to the buffer
4768 * Intended just for the debug routine
4769 */
4770static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00004771xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004772 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00004773 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004774
4775 if (node == NULL) return;
4776 if (glob) strcat(buf, "(");
4777 cur = node;
4778 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004779 len = strlen(buf);
4780 if (size - len < 50) {
4781 if ((size - len > 4) && (buf[len - 1] != '.'))
4782 strcat(buf, " ...");
4783 return;
4784 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004785 switch (cur->type) {
4786 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004787 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004788 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004789 if ((size - len > 4) && (buf[len - 1] != '.'))
4790 strcat(buf, " ...");
4791 return;
4792 }
4793 strcat(buf, (char *) cur->ns->prefix);
4794 strcat(buf, ":");
4795 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004796 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004797 if ((size - len > 4) && (buf[len - 1] != '.'))
4798 strcat(buf, " ...");
4799 return;
4800 }
4801 strcat(buf, (char *) cur->name);
4802 if (cur->next != NULL)
4803 strcat(buf, " ");
4804 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004805 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004806 if (xmlIsBlankNode(cur))
4807 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004808 case XML_CDATA_SECTION_NODE:
4809 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004810 strcat(buf, "CDATA");
4811 if (cur->next != NULL)
4812 strcat(buf, " ");
4813 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004814 case XML_ATTRIBUTE_NODE:
4815 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004816#ifdef LIBXML_DOCB_ENABLED
4817 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004818#endif
4819 case XML_HTML_DOCUMENT_NODE:
4820 case XML_DOCUMENT_TYPE_NODE:
4821 case XML_DOCUMENT_FRAG_NODE:
4822 case XML_NOTATION_NODE:
4823 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004824 strcat(buf, "???");
4825 if (cur->next != NULL)
4826 strcat(buf, " ");
4827 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004828 case XML_ENTITY_NODE:
4829 case XML_PI_NODE:
4830 case XML_DTD_NODE:
4831 case XML_COMMENT_NODE:
4832 case XML_ELEMENT_DECL:
4833 case XML_ATTRIBUTE_DECL:
4834 case XML_ENTITY_DECL:
4835 case XML_XINCLUDE_START:
4836 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004837 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004838 }
4839 cur = cur->next;
4840 }
4841 if (glob) strcat(buf, ")");
4842}
4843
4844/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004845 * xmlValidateElementContent:
4846 * @ctxt: the validation context
4847 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004848 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004849 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004850 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004851 *
4852 * Try to validate the content model of an element
4853 *
4854 * returns 1 if valid or 0 if not and -1 in case of error
4855 */
4856
4857static int
4858xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004859 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004860 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00004861#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00004862 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00004863#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00004864 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004865 xmlElementContentPtr cont;
4866 const xmlChar *name;
4867
4868 if (elemDecl == NULL)
4869 return(-1);
4870 cont = elemDecl->content;
4871 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004872
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004873#ifdef LIBXML_REGEXP_ENABLED
4874 /* Build the regexp associated to the content model */
4875 if (elemDecl->contModel == NULL)
4876 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4877 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004878 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004879 } else {
4880 xmlRegExecCtxtPtr exec;
4881
Daniel Veillardec498e12003-02-05 11:01:50 +00004882 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
4883 return(-1);
4884 }
Daniel Veillard01992e02002-10-09 10:20:30 +00004885 ctxt->nodeMax = 0;
4886 ctxt->nodeNr = 0;
4887 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004888 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4889 if (exec != NULL) {
4890 cur = child;
4891 while (cur != NULL) {
4892 switch (cur->type) {
4893 case XML_ENTITY_REF_NODE:
4894 /*
4895 * Push the current node to be able to roll back
4896 * and process within the entity
4897 */
4898 if ((cur->children != NULL) &&
4899 (cur->children->children != NULL)) {
4900 nodeVPush(ctxt, cur);
4901 cur = cur->children->children;
4902 continue;
4903 }
4904 break;
4905 case XML_TEXT_NODE:
4906 if (xmlIsBlankNode(cur))
4907 break;
4908 ret = 0;
4909 goto fail;
4910 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00004911 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004912 ret = 0;
4913 goto fail;
4914 case XML_ELEMENT_NODE:
4915 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004916 xmlChar fn[50];
4917 xmlChar *fullname;
4918
4919 fullname = xmlBuildQName(cur->name,
4920 cur->ns->prefix, fn, 50);
4921 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004922 ret = -1;
4923 goto fail;
4924 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004925 ret = xmlRegExecPushString(exec, fullname, NULL);
4926 if ((fullname != fn) && (fullname != cur->name))
4927 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004928 } else {
4929 ret = xmlRegExecPushString(exec, cur->name, NULL);
4930 }
4931 break;
4932 default:
4933 break;
4934 }
4935 /*
4936 * Switch to next element
4937 */
4938 cur = cur->next;
4939 while (cur == NULL) {
4940 cur = nodeVPop(ctxt);
4941 if (cur == NULL)
4942 break;
4943 cur = cur->next;
4944 }
4945 }
4946 ret = xmlRegExecPushString(exec, NULL, NULL);
4947fail:
4948 xmlRegFreeExecCtxt(exec);
4949 }
4950 }
4951#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004952 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004953 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004954 */
4955 ctxt->vstateMax = 8;
4956 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
4957 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
4958 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004959 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004960 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004961 }
4962 /*
4963 * The first entry in the stack is reserved to the current state
4964 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00004965 ctxt->nodeMax = 0;
4966 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00004967 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004968 ctxt->vstate = &ctxt->vstateTab[0];
4969 ctxt->vstateNr = 1;
4970 CONT = cont;
4971 NODE = child;
4972 DEPTH = 0;
4973 OCCURS = 0;
4974 STATE = 0;
4975 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004976 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004977 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
4978 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00004979 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004980 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004981 /*
4982 * An entities reference appeared at this level.
4983 * Buid a minimal representation of this node content
4984 * sufficient to run the validation process on it
4985 */
4986 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004987 cur = child;
4988 while (cur != NULL) {
4989 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004990 case XML_ENTITY_REF_NODE:
4991 /*
4992 * Push the current node to be able to roll back
4993 * and process within the entity
4994 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004995 if ((cur->children != NULL) &&
4996 (cur->children->children != NULL)) {
4997 nodeVPush(ctxt, cur);
4998 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004999 continue;
5000 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005001 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005002 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005003 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005004 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005005 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005006 case XML_CDATA_SECTION_NODE:
5007 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005008 case XML_ELEMENT_NODE:
5009 /*
5010 * Allocate a new node and minimally fills in
5011 * what's required
5012 */
5013 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5014 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005015 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005016 xmlFreeNodeList(repl);
5017 ret = -1;
5018 goto done;
5019 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005020 tmp->type = cur->type;
5021 tmp->name = cur->name;
5022 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005023 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005024 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005025 if (repl == NULL)
5026 repl = last = tmp;
5027 else {
5028 last->next = tmp;
5029 last = tmp;
5030 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005031 if (cur->type == XML_CDATA_SECTION_NODE) {
5032 /*
5033 * E59 spaces in CDATA does not match the
5034 * nonterminal S
5035 */
5036 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5037 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005038 break;
5039 default:
5040 break;
5041 }
5042 /*
5043 * Switch to next element
5044 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005045 cur = cur->next;
5046 while (cur == NULL) {
5047 cur = nodeVPop(ctxt);
5048 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005049 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005050 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005051 }
5052 }
5053
5054 /*
5055 * Relaunch the validation
5056 */
5057 ctxt->vstate = &ctxt->vstateTab[0];
5058 ctxt->vstateNr = 1;
5059 CONT = cont;
5060 NODE = repl;
5061 DEPTH = 0;
5062 OCCURS = 0;
5063 STATE = 0;
5064 ret = xmlValidateElementType(ctxt);
5065 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005066#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005067 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005068 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5069 char expr[5000];
5070 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005071
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005072 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005073 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005074 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005075#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005076 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005077 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005078 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005079#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005080 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005081
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005082 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005083 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5084 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5085 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005086 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005087 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5088 "Element content does not follow the DTD, expecting %s, got %s\n",
5089 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005090 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005091 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005092 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005093 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005094 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005095 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005096 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005097 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5098 "Element content does not follow the DTD\n",
5099 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005100 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005101 }
5102 ret = 0;
5103 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005104 if (ret == -3)
5105 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005106
Daniel Veillard23e73572002-09-19 19:56:43 +00005107#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005108done:
5109 /*
5110 * Deallocate the copy if done, and free up the validation stack
5111 */
5112 while (repl != NULL) {
5113 tmp = repl->next;
5114 xmlFree(repl);
5115 repl = tmp;
5116 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005117 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005118 if (ctxt->vstateTab != NULL) {
5119 xmlFree(ctxt->vstateTab);
5120 ctxt->vstateTab = NULL;
5121 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005122#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005123 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005124 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005125 if (ctxt->nodeTab != NULL) {
5126 xmlFree(ctxt->nodeTab);
5127 ctxt->nodeTab = NULL;
5128 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005129 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005130
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005131}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005132
Owen Taylor3473f882001-02-23 17:55:21 +00005133/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005134 * xmlValidateCdataElement:
5135 * @ctxt: the validation context
5136 * @doc: a document instance
5137 * @elem: an element instance
5138 *
5139 * Check that an element follows #CDATA
5140 *
5141 * returns 1 if valid or 0 otherwise
5142 */
5143static int
5144xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5145 xmlNodePtr elem) {
5146 int ret = 1;
5147 xmlNodePtr cur, child;
5148
Daniel Veillardceb09b92002-10-04 11:46:37 +00005149 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005150 return(0);
5151
5152 child = elem->children;
5153
5154 cur = child;
5155 while (cur != NULL) {
5156 switch (cur->type) {
5157 case XML_ENTITY_REF_NODE:
5158 /*
5159 * Push the current node to be able to roll back
5160 * and process within the entity
5161 */
5162 if ((cur->children != NULL) &&
5163 (cur->children->children != NULL)) {
5164 nodeVPush(ctxt, cur);
5165 cur = cur->children->children;
5166 continue;
5167 }
5168 break;
5169 case XML_COMMENT_NODE:
5170 case XML_PI_NODE:
5171 case XML_TEXT_NODE:
5172 case XML_CDATA_SECTION_NODE:
5173 break;
5174 default:
5175 ret = 0;
5176 goto done;
5177 }
5178 /*
5179 * Switch to next element
5180 */
5181 cur = cur->next;
5182 while (cur == NULL) {
5183 cur = nodeVPop(ctxt);
5184 if (cur == NULL)
5185 break;
5186 cur = cur->next;
5187 }
5188 }
5189done:
5190 ctxt->nodeMax = 0;
5191 ctxt->nodeNr = 0;
5192 if (ctxt->nodeTab != NULL) {
5193 xmlFree(ctxt->nodeTab);
5194 ctxt->nodeTab = NULL;
5195 }
5196 return(ret);
5197}
5198
5199/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005200 * xmlValidateCheckMixed:
5201 * @ctxt: the validation context
5202 * @cont: the mixed content model
5203 * @qname: the qualified name as appearing in the serialization
5204 *
5205 * Check if the given node is part of the content model.
5206 *
5207 * Returns 1 if yes, 0 if no, -1 in case of error
5208 */
5209static int
5210xmlValidateCheckMixed(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
5211 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005212 const xmlChar *name;
5213 int plen;
5214 name = xmlSplitQName3(qname, &plen);
5215
5216 if (name == NULL) {
5217 while (cont != NULL) {
5218 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5219 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5220 return(1);
5221 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5222 (cont->c1 != NULL) &&
5223 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5224 if ((cont->c1->prefix == NULL) &&
5225 (xmlStrEqual(cont->c1->name, qname)))
5226 return(1);
5227 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5228 (cont->c1 == NULL) ||
5229 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005230 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5231 "Internal: MIXED struct corrupted\n",
5232 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005233 break;
5234 }
5235 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005236 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005237 } else {
5238 while (cont != NULL) {
5239 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5240 if ((cont->prefix != NULL) &&
5241 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5242 (xmlStrEqual(cont->name, name)))
5243 return(1);
5244 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5245 (cont->c1 != NULL) &&
5246 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5247 if ((cont->c1->prefix != NULL) &&
5248 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5249 (xmlStrEqual(cont->c1->name, name)))
5250 return(1);
5251 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5252 (cont->c1 == NULL) ||
5253 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005254 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5255 "Internal: MIXED struct corrupted\n",
5256 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005257 break;
5258 }
5259 cont = cont->c2;
5260 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005261 }
5262 return(0);
5263}
5264
5265/**
5266 * xmlValidGetElemDecl:
5267 * @ctxt: the validation context
5268 * @doc: a document instance
5269 * @elem: an element instance
5270 * @extsubset: pointer, (out) indicate if the declaration was found
5271 * in the external subset.
5272 *
5273 * Finds a declaration associated to an element in the document.
5274 *
5275 * returns the pointer to the declaration or NULL if not found.
5276 */
5277static xmlElementPtr
5278xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5279 xmlNodePtr elem, int *extsubset) {
5280 xmlElementPtr elemDecl = NULL;
5281 const xmlChar *prefix = NULL;
5282
5283 if ((elem == NULL) || (elem->name == NULL)) return(NULL);
5284 if (extsubset != NULL)
5285 *extsubset = 0;
5286
5287 /*
5288 * Fetch the declaration for the qualified name
5289 */
5290 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5291 prefix = elem->ns->prefix;
5292
5293 if (prefix != NULL) {
5294 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5295 elem->name, prefix);
5296 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5297 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5298 elem->name, prefix);
5299 if ((elemDecl != NULL) && (extsubset != NULL))
5300 *extsubset = 1;
5301 }
5302 }
5303
5304 /*
5305 * Fetch the declaration for the non qualified name
5306 * This is "non-strict" validation should be done on the
5307 * full QName but in that case being flexible makes sense.
5308 */
5309 if (elemDecl == NULL) {
5310 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5311 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5312 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5313 if ((elemDecl != NULL) && (extsubset != NULL))
5314 *extsubset = 1;
5315 }
5316 }
5317 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005318 xmlErrValidNode(ctxt, elem,
5319 XML_DTD_UNKNOWN_ELEM,
5320 "No declaration for element %s\n",
5321 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005322 }
5323 return(elemDecl);
5324}
5325
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005326#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005327/**
5328 * xmlValidatePushElement:
5329 * @ctxt: the validation context
5330 * @doc: a document instance
5331 * @elem: an element instance
5332 * @qname: the qualified name as appearing in the serialization
5333 *
5334 * Push a new element start on the validation stack.
5335 *
5336 * returns 1 if no validation problem was found or 0 otherwise
5337 */
5338int
5339xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5340 xmlNodePtr elem, const xmlChar *qname) {
5341 int ret = 1;
5342 xmlElementPtr eDecl;
5343 int extsubset = 0;
5344
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005345/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005346 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5347 xmlValidStatePtr state = ctxt->vstate;
5348 xmlElementPtr elemDecl;
5349
5350 /*
5351 * Check the new element agaisnt the content model of the new elem.
5352 */
5353 if (state->elemDecl != NULL) {
5354 elemDecl = state->elemDecl;
5355
5356 switch(elemDecl->etype) {
5357 case XML_ELEMENT_TYPE_UNDEFINED:
5358 ret = 0;
5359 break;
5360 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005361 xmlErrValidNode(ctxt, state->node,
5362 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005363 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005364 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005365 ret = 0;
5366 break;
5367 case XML_ELEMENT_TYPE_ANY:
5368 /* I don't think anything is required then */
5369 break;
5370 case XML_ELEMENT_TYPE_MIXED:
5371 /* simple case of declared as #PCDATA */
5372 if ((elemDecl->content != NULL) &&
5373 (elemDecl->content->type ==
5374 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005375 xmlErrValidNode(ctxt, state->node,
5376 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005377 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005378 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005379 ret = 0;
5380 } else {
5381 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5382 qname);
5383 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005384 xmlErrValidNode(ctxt, state->node,
5385 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005386 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005387 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005388 }
5389 }
5390 break;
5391 case XML_ELEMENT_TYPE_ELEMENT:
5392 /*
5393 * TODO:
5394 * VC: Standalone Document Declaration
5395 * - element types with element content, if white space
5396 * occurs directly within any instance of those types.
5397 */
5398 if (state->exec != NULL) {
5399 ret = xmlRegExecPushString(state->exec, qname, NULL);
5400 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005401 xmlErrValidNode(ctxt, state->node,
5402 XML_DTD_CONTENT_MODEL,
5403 "Element %s content does not follow the DTD, Misplaced %s\n",
5404 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005405 ret = 0;
5406 } else {
5407 ret = 1;
5408 }
5409 }
5410 break;
5411 }
5412 }
5413 }
5414 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5415 vstateVPush(ctxt, eDecl, elem);
5416 return(ret);
5417}
5418
5419/**
5420 * xmlValidatePushCData:
5421 * @ctxt: the validation context
5422 * @data: some character data read
5423 * @len: the lenght of the data
5424 *
5425 * check the CData parsed for validation in the current stack
5426 *
5427 * returns 1 if no validation problem was found or 0 otherwise
5428 */
5429int
5430xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5431 int ret = 1;
5432
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005433/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005434 if (len <= 0)
5435 return(ret);
5436 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5437 xmlValidStatePtr state = ctxt->vstate;
5438 xmlElementPtr elemDecl;
5439
5440 /*
5441 * Check the new element agaisnt the content model of the new elem.
5442 */
5443 if (state->elemDecl != NULL) {
5444 elemDecl = state->elemDecl;
5445
5446 switch(elemDecl->etype) {
5447 case XML_ELEMENT_TYPE_UNDEFINED:
5448 ret = 0;
5449 break;
5450 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005451 xmlErrValidNode(ctxt, state->node,
5452 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005453 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005454 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005455 ret = 0;
5456 break;
5457 case XML_ELEMENT_TYPE_ANY:
5458 break;
5459 case XML_ELEMENT_TYPE_MIXED:
5460 break;
5461 case XML_ELEMENT_TYPE_ELEMENT:
5462 if (len > 0) {
5463 int i;
5464
5465 for (i = 0;i < len;i++) {
5466 if (!IS_BLANK(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005467 xmlErrValidNode(ctxt, state->node,
5468 XML_DTD_CONTENT_MODEL,
5469 "Element %s content does not follow the DTD, Text not allowed\n",
5470 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005471 ret = 0;
5472 goto done;
5473 }
5474 }
5475 /*
5476 * TODO:
5477 * VC: Standalone Document Declaration
5478 * element types with element content, if white space
5479 * occurs directly within any instance of those types.
5480 */
5481 }
5482 break;
5483 }
5484 }
5485 }
5486done:
5487 return(ret);
5488}
5489
5490/**
5491 * xmlValidatePopElement:
5492 * @ctxt: the validation context
5493 * @doc: a document instance
5494 * @elem: an element instance
5495 * @qname: the qualified name as appearing in the serialization
5496 *
5497 * Pop the element end from the validation stack.
5498 *
5499 * returns 1 if no validation problem was found or 0 otherwise
5500 */
5501int
5502xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005503 xmlNodePtr elem ATTRIBUTE_UNUSED,
5504 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005505 int ret = 1;
5506
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005507/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005508 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5509 xmlValidStatePtr state = ctxt->vstate;
5510 xmlElementPtr elemDecl;
5511
5512 /*
5513 * Check the new element agaisnt the content model of the new elem.
5514 */
5515 if (state->elemDecl != NULL) {
5516 elemDecl = state->elemDecl;
5517
5518 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5519 if (state->exec != NULL) {
5520 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5521 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005522 xmlErrValidNode(ctxt, state->node,
5523 XML_DTD_CONTENT_MODEL,
5524 "Element %s content does not follow the DTD, Expecting more child\n",
5525 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005526 } else {
5527 /*
5528 * previous validation errors should not generate
5529 * a new one here
5530 */
5531 ret = 1;
5532 }
5533 }
5534 }
5535 }
5536 vstateVPop(ctxt);
5537 }
5538 return(ret);
5539}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005540#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005541
5542/**
Owen Taylor3473f882001-02-23 17:55:21 +00005543 * xmlValidateOneElement:
5544 * @ctxt: the validation context
5545 * @doc: a document instance
5546 * @elem: an element instance
5547 *
5548 * Try to validate a single element and it's attributes,
5549 * basically it does the following checks as described by the
5550 * XML-1.0 recommendation:
5551 * - [ VC: Element Valid ]
5552 * - [ VC: Required Attribute ]
5553 * Then call xmlValidateOneAttribute() for each attribute present.
5554 *
5555 * The ID/IDREF checkings are done separately
5556 *
5557 * returns 1 if valid or 0 otherwise
5558 */
5559
5560int
5561xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5562 xmlNodePtr elem) {
5563 xmlElementPtr elemDecl = NULL;
5564 xmlElementContentPtr cont;
5565 xmlAttributePtr attr;
5566 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005567 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005568 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005569 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005570
5571 CHECK_DTD;
5572
5573 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005574 switch (elem->type) {
5575 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005576 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5577 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005578 return(0);
5579 case XML_TEXT_NODE:
5580 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005581 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5582 "Text element has children !\n",
5583 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005584 return(0);
5585 }
5586 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005587 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5588 "Text element has attribute !\n",
5589 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005590 return(0);
5591 }
5592 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005593 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5594 "Text element has namespace !\n",
5595 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005596 return(0);
5597 }
5598 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005599 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5600 "Text element has namespace !\n",
5601 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005602 return(0);
5603 }
5604 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005605 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5606 "Text element has no content !\n",
5607 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005608 return(0);
5609 }
5610 return(1);
5611 case XML_XINCLUDE_START:
5612 case XML_XINCLUDE_END:
5613 return(1);
5614 case XML_CDATA_SECTION_NODE:
5615 case XML_ENTITY_REF_NODE:
5616 case XML_PI_NODE:
5617 case XML_COMMENT_NODE:
5618 return(1);
5619 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005620 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5621 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005622 return(0);
5623 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005624 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5625 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005626 return(0);
5627 case XML_DOCUMENT_NODE:
5628 case XML_DOCUMENT_TYPE_NODE:
5629 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005630 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5631 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005632 return(0);
5633 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005634 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5635 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005636 return(0);
5637 case XML_ELEMENT_NODE:
5638 break;
5639 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005640 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5641 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005642 return(0);
5643 }
Owen Taylor3473f882001-02-23 17:55:21 +00005644
5645 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005646 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005647 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005648 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5649 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005650 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005651
Daniel Veillardea7751d2002-12-20 00:16:24 +00005652 /*
5653 * If vstateNr is not zero that means continuous validation is
5654 * activated, do not try to check the content model at that level.
5655 */
5656 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005657 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005658 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005659 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005660 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5661 "No declaration for element %s\n",
5662 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005663 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005664 case XML_ELEMENT_TYPE_EMPTY:
5665 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005666 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005667 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005668 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005669 ret = 0;
5670 }
5671 break;
5672 case XML_ELEMENT_TYPE_ANY:
5673 /* I don't think anything is required then */
5674 break;
5675 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005676
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005677 /* simple case of declared as #PCDATA */
5678 if ((elemDecl->content != NULL) &&
5679 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5680 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5681 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005682 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005683 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005684 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005685 }
5686 break;
5687 }
Owen Taylor3473f882001-02-23 17:55:21 +00005688 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005689 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005690 while (child != NULL) {
5691 if (child->type == XML_ELEMENT_NODE) {
5692 name = child->name;
5693 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005694 xmlChar fn[50];
5695 xmlChar *fullname;
5696
5697 fullname = xmlBuildQName(child->name, child->ns->prefix,
5698 fn, 50);
5699 if (fullname == NULL)
5700 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005701 cont = elemDecl->content;
5702 while (cont != NULL) {
5703 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005704 if (xmlStrEqual(cont->name, fullname))
5705 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005706 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5707 (cont->c1 != NULL) &&
5708 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005709 if (xmlStrEqual(cont->c1->name, fullname))
5710 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005711 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5712 (cont->c1 == NULL) ||
5713 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005714 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5715 "Internal: MIXED struct corrupted\n",
5716 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005717 break;
5718 }
5719 cont = cont->c2;
5720 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005721 if ((fullname != fn) && (fullname != child->name))
5722 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005723 if (cont != NULL)
5724 goto child_ok;
5725 }
5726 cont = elemDecl->content;
5727 while (cont != NULL) {
5728 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5729 if (xmlStrEqual(cont->name, name)) break;
5730 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5731 (cont->c1 != NULL) &&
5732 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5733 if (xmlStrEqual(cont->c1->name, name)) break;
5734 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5735 (cont->c1 == NULL) ||
5736 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005737 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5738 "Internal: MIXED struct corrupted\n",
5739 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005740 break;
5741 }
5742 cont = cont->c2;
5743 }
5744 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005745 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00005746 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005747 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005748 ret = 0;
5749 }
5750 }
5751child_ok:
5752 child = child->next;
5753 }
5754 break;
5755 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005756 if ((doc->standalone == 1) && (extsubset == 1)) {
5757 /*
5758 * VC: Standalone Document Declaration
5759 * - element types with element content, if white space
5760 * occurs directly within any instance of those types.
5761 */
5762 child = elem->children;
5763 while (child != NULL) {
5764 if (child->type == XML_TEXT_NODE) {
5765 const xmlChar *content = child->content;
5766
5767 while (IS_BLANK(*content))
5768 content++;
5769 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005770 xmlErrValidNode(ctxt, elem,
5771 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005772"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005773 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005774 ret = 0;
5775 break;
5776 }
5777 }
5778 child =child->next;
5779 }
5780 }
Owen Taylor3473f882001-02-23 17:55:21 +00005781 child = elem->children;
5782 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005783 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005784 if (tmp <= 0)
5785 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005786 break;
5787 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005788 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00005789
5790 /* [ VC: Required Attribute ] */
5791 attr = elemDecl->attributes;
5792 while (attr != NULL) {
5793 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005794 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005795
Daniel Veillarde4301c82002-02-13 13:32:35 +00005796 if ((attr->prefix == NULL) &&
5797 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5798 xmlNsPtr ns;
5799
5800 ns = elem->nsDef;
5801 while (ns != NULL) {
5802 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005803 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005804 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00005805 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005806 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5807 xmlNsPtr ns;
5808
5809 ns = elem->nsDef;
5810 while (ns != NULL) {
5811 if (xmlStrEqual(attr->name, ns->prefix))
5812 goto found;
5813 ns = ns->next;
5814 }
5815 } else {
5816 xmlAttrPtr attrib;
5817
5818 attrib = elem->properties;
5819 while (attrib != NULL) {
5820 if (xmlStrEqual(attrib->name, attr->name)) {
5821 if (attr->prefix != NULL) {
5822 xmlNsPtr nameSpace = attrib->ns;
5823
5824 if (nameSpace == NULL)
5825 nameSpace = elem->ns;
5826 /*
5827 * qualified names handling is problematic, having a
5828 * different prefix should be possible but DTDs don't
5829 * allow to define the URI instead of the prefix :-(
5830 */
5831 if (nameSpace == NULL) {
5832 if (qualified < 0)
5833 qualified = 0;
5834 } else if (!xmlStrEqual(nameSpace->prefix,
5835 attr->prefix)) {
5836 if (qualified < 1)
5837 qualified = 1;
5838 } else
5839 goto found;
5840 } else {
5841 /*
5842 * We should allow applications to define namespaces
5843 * for their application even if the DTD doesn't
5844 * carry one, otherwise, basically we would always
5845 * break.
5846 */
5847 goto found;
5848 }
5849 }
5850 attrib = attrib->next;
5851 }
Owen Taylor3473f882001-02-23 17:55:21 +00005852 }
5853 if (qualified == -1) {
5854 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005855 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005856 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005857 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005858 ret = 0;
5859 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005860 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005861 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005862 elem->name, attr->prefix,attr->name);
5863 ret = 0;
5864 }
5865 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005866 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005867 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005868 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005869 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005870 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005871 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005872 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005873 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005874 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5875 /*
5876 * Special tests checking #FIXED namespace declarations
5877 * have the right value since this is not done as an
5878 * attribute checking
5879 */
5880 if ((attr->prefix == NULL) &&
5881 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5882 xmlNsPtr ns;
5883
5884 ns = elem->nsDef;
5885 while (ns != NULL) {
5886 if (ns->prefix == NULL) {
5887 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005888 xmlErrValidNode(ctxt, elem,
5889 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00005890 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005891 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005892 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005893 }
5894 goto found;
5895 }
5896 ns = ns->next;
5897 }
5898 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5899 xmlNsPtr ns;
5900
5901 ns = elem->nsDef;
5902 while (ns != NULL) {
5903 if (xmlStrEqual(attr->name, ns->prefix)) {
5904 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005905 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005906 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005907 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005908 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005909 }
5910 goto found;
5911 }
5912 ns = ns->next;
5913 }
5914 }
Owen Taylor3473f882001-02-23 17:55:21 +00005915 }
5916found:
5917 attr = attr->nexth;
5918 }
5919 return(ret);
5920}
5921
5922/**
5923 * xmlValidateRoot:
5924 * @ctxt: the validation context
5925 * @doc: a document instance
5926 *
5927 * Try to validate a the root element
5928 * basically it does the following check as described by the
5929 * XML-1.0 recommendation:
5930 * - [ VC: Root Element Type ]
5931 * it doesn't try to recurse or apply other check to the element
5932 *
5933 * returns 1 if valid or 0 otherwise
5934 */
5935
5936int
5937xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
5938 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00005939 int ret;
5940
Owen Taylor3473f882001-02-23 17:55:21 +00005941 if (doc == NULL) return(0);
5942
5943 root = xmlDocGetRootElement(doc);
5944 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005945 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
5946 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005947 return(0);
5948 }
5949
5950 /*
5951 * When doing post validation against a separate DTD, those may
5952 * no internal subset has been generated
5953 */
5954 if ((doc->intSubset != NULL) &&
5955 (doc->intSubset->name != NULL)) {
5956 /*
5957 * Check first the document root against the NQName
5958 */
5959 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
5960 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005961 xmlChar fn[50];
5962 xmlChar *fullname;
5963
5964 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
5965 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005966 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00005967 return(0);
5968 }
5969 ret = xmlStrEqual(doc->intSubset->name, fullname);
5970 if ((fullname != fn) && (fullname != root->name))
5971 xmlFree(fullname);
5972 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00005973 goto name_ok;
5974 }
5975 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
5976 (xmlStrEqual(root->name, BAD_CAST "html")))
5977 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005978 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
5979 "root and DTD name do not match '%s' and '%s'\n",
5980 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005981 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005982 }
5983 }
5984name_ok:
5985 return(1);
5986}
5987
5988
5989/**
5990 * xmlValidateElement:
5991 * @ctxt: the validation context
5992 * @doc: a document instance
5993 * @elem: an element instance
5994 *
5995 * Try to validate the subtree under an element
5996 *
5997 * returns 1 if valid or 0 otherwise
5998 */
5999
6000int
6001xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6002 xmlNodePtr child;
6003 xmlAttrPtr attr;
6004 xmlChar *value;
6005 int ret = 1;
6006
6007 if (elem == NULL) return(0);
6008
6009 /*
6010 * XInclude elements were added after parsing in the infoset,
6011 * they don't really mean anything validation wise.
6012 */
6013 if ((elem->type == XML_XINCLUDE_START) ||
6014 (elem->type == XML_XINCLUDE_END))
6015 return(1);
6016
6017 CHECK_DTD;
6018
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006019 /*
6020 * Entities references have to be handled separately
6021 */
6022 if (elem->type == XML_ENTITY_REF_NODE) {
6023 return(1);
6024 }
6025
Owen Taylor3473f882001-02-23 17:55:21 +00006026 ret &= xmlValidateOneElement(ctxt, doc, elem);
6027 attr = elem->properties;
6028 while(attr != NULL) {
6029 value = xmlNodeListGetString(doc, attr->children, 0);
6030 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6031 if (value != NULL)
6032 xmlFree(value);
6033 attr= attr->next;
6034 }
6035 child = elem->children;
6036 while (child != NULL) {
6037 ret &= xmlValidateElement(ctxt, doc, child);
6038 child = child->next;
6039 }
6040
6041 return(ret);
6042}
6043
Daniel Veillard8730c562001-02-26 10:49:57 +00006044/**
6045 * xmlValidateRef:
6046 * @ref: A reference to be validated
6047 * @ctxt: Validation context
6048 * @name: Name of ID we are searching for
6049 *
6050 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006051static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006052xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006053 const xmlChar *name) {
6054 xmlAttrPtr id;
6055 xmlAttrPtr attr;
6056
6057 if (ref == NULL)
6058 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006059 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006060 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006061 attr = ref->attr;
6062 if (attr == NULL) {
6063 xmlChar *dup, *str = NULL, *cur, save;
6064
6065 dup = xmlStrdup(name);
6066 if (dup == NULL) {
6067 ctxt->valid = 0;
6068 return;
6069 }
6070 cur = dup;
6071 while (*cur != 0) {
6072 str = cur;
6073 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6074 save = *cur;
6075 *cur = 0;
6076 id = xmlGetID(ctxt->doc, str);
6077 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006078 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006079 "attribute %s line %d references an unknown ID \"%s\"\n",
6080 ref->name, ref->lineno, str);
6081 ctxt->valid = 0;
6082 }
6083 if (save == 0)
6084 break;
6085 *cur = save;
6086 while (IS_BLANK(*cur)) cur++;
6087 }
6088 xmlFree(dup);
6089 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006090 id = xmlGetID(ctxt->doc, name);
6091 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006092 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006093 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006094 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006095 ctxt->valid = 0;
6096 }
6097 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6098 xmlChar *dup, *str = NULL, *cur, save;
6099
6100 dup = xmlStrdup(name);
6101 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006102 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006103 ctxt->valid = 0;
6104 return;
6105 }
6106 cur = dup;
6107 while (*cur != 0) {
6108 str = cur;
6109 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6110 save = *cur;
6111 *cur = 0;
6112 id = xmlGetID(ctxt->doc, str);
6113 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006114 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006115 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006116 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006117 ctxt->valid = 0;
6118 }
6119 if (save == 0)
6120 break;
6121 *cur = save;
6122 while (IS_BLANK(*cur)) cur++;
6123 }
6124 xmlFree(dup);
6125 }
6126}
6127
6128/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006129 * xmlWalkValidateList:
6130 * @data: Contents of current link
6131 * @user: Value supplied by the user
6132 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006133 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006134 */
6135static int
6136xmlWalkValidateList(const void *data, const void *user)
6137{
6138 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6139 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6140 return 1;
6141}
6142
6143/**
6144 * xmlValidateCheckRefCallback:
6145 * @ref_list: List of references
6146 * @ctxt: Validation context
6147 * @name: Name of ID we are searching for
6148 *
6149 */
6150static void
6151xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6152 const xmlChar *name) {
6153 xmlValidateMemo memo;
6154
6155 if (ref_list == NULL)
6156 return;
6157 memo.ctxt = ctxt;
6158 memo.name = name;
6159
6160 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6161
6162}
6163
6164/**
Owen Taylor3473f882001-02-23 17:55:21 +00006165 * xmlValidateDocumentFinal:
6166 * @ctxt: the validation context
6167 * @doc: a document instance
6168 *
6169 * Does the final step for the document validation once all the
6170 * incremental validation steps have been completed
6171 *
6172 * basically it does the following checks described by the XML Rec
6173 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006174 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006175 *
6176 * returns 1 if valid or 0 otherwise
6177 */
6178
6179int
6180xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6181 xmlRefTablePtr table;
6182
6183 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006184 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6185 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006186 return(0);
6187 }
6188
6189 /*
6190 * Check all the NOTATION/NOTATIONS attributes
6191 */
6192 /*
6193 * Check all the ENTITY/ENTITIES attributes definition for validity
6194 */
6195 /*
6196 * Check all the IDREF/IDREFS attributes definition for validity
6197 */
6198 table = (xmlRefTablePtr) doc->refs;
6199 ctxt->doc = doc;
6200 ctxt->valid = 1;
6201 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6202 return(ctxt->valid);
6203}
6204
6205/**
6206 * xmlValidateDtd:
6207 * @ctxt: the validation context
6208 * @doc: a document instance
6209 * @dtd: a dtd instance
6210 *
6211 * Try to validate the document against the dtd instance
6212 *
6213 * basically it does check all the definitions in the DtD.
6214 *
6215 * returns 1 if valid or 0 otherwise
6216 */
6217
6218int
6219xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6220 int ret;
6221 xmlDtdPtr oldExt;
6222 xmlNodePtr root;
6223
6224 if (dtd == NULL) return(0);
6225 if (doc == NULL) return(0);
6226 oldExt = doc->extSubset;
6227 doc->extSubset = dtd;
6228 ret = xmlValidateRoot(ctxt, doc);
6229 if (ret == 0) {
6230 doc->extSubset = oldExt;
6231 return(ret);
6232 }
6233 if (doc->ids != NULL) {
6234 xmlFreeIDTable(doc->ids);
6235 doc->ids = NULL;
6236 }
6237 if (doc->refs != NULL) {
6238 xmlFreeRefTable(doc->refs);
6239 doc->refs = NULL;
6240 }
6241 root = xmlDocGetRootElement(doc);
6242 ret = xmlValidateElement(ctxt, doc, root);
6243 ret &= xmlValidateDocumentFinal(ctxt, doc);
6244 doc->extSubset = oldExt;
6245 return(ret);
6246}
6247
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006248static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006249xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6250 const xmlChar *name ATTRIBUTE_UNUSED) {
6251 if (cur == NULL)
6252 return;
6253 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6254 xmlChar *notation = cur->content;
6255
Daniel Veillard878eab02002-02-19 13:46:09 +00006256 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006257 int ret;
6258
6259 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6260 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006261 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006262 }
6263 }
6264 }
6265}
6266
6267static void
Owen Taylor3473f882001-02-23 17:55:21 +00006268xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006269 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006270 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006271 xmlDocPtr doc;
6272 xmlElementPtr elem;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006273
Owen Taylor3473f882001-02-23 17:55:21 +00006274 if (cur == NULL)
6275 return;
6276 switch (cur->atype) {
6277 case XML_ATTRIBUTE_CDATA:
6278 case XML_ATTRIBUTE_ID:
6279 case XML_ATTRIBUTE_IDREF :
6280 case XML_ATTRIBUTE_IDREFS:
6281 case XML_ATTRIBUTE_NMTOKEN:
6282 case XML_ATTRIBUTE_NMTOKENS:
6283 case XML_ATTRIBUTE_ENUMERATION:
6284 break;
6285 case XML_ATTRIBUTE_ENTITY:
6286 case XML_ATTRIBUTE_ENTITIES:
6287 case XML_ATTRIBUTE_NOTATION:
6288 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006289
6290 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6291 cur->atype, cur->defaultValue);
6292 if ((ret == 0) && (ctxt->valid == 1))
6293 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006294 }
6295 if (cur->tree != NULL) {
6296 xmlEnumerationPtr tree = cur->tree;
6297 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006298 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006299 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006300 if ((ret == 0) && (ctxt->valid == 1))
6301 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006302 tree = tree->next;
6303 }
6304 }
6305 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006306 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6307 doc = cur->doc;
6308 if ((doc == NULL) || (cur->elem == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006309 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006310 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006311 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006312 return;
6313 }
6314 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6315 if (elem == NULL)
6316 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
6317 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006318 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006319 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006320 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006321 return;
6322 }
6323 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006324 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006325 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006326 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006327 ctxt->valid = 0;
6328 }
6329 }
Owen Taylor3473f882001-02-23 17:55:21 +00006330}
6331
6332/**
6333 * xmlValidateDtdFinal:
6334 * @ctxt: the validation context
6335 * @doc: a document instance
6336 *
6337 * Does the final step for the dtds validation once all the
6338 * subsets have been parsed
6339 *
6340 * basically it does the following checks described by the XML Rec
6341 * - check that ENTITY and ENTITIES type attributes default or
6342 * possible values matches one of the defined entities.
6343 * - check that NOTATION type attributes default or
6344 * possible values matches one of the defined notations.
6345 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006346 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006347 */
6348
6349int
6350xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006351 xmlDtdPtr dtd;
6352 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006353 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006354
6355 if (doc == NULL) return(0);
6356 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6357 return(0);
6358 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006359 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006360 dtd = doc->intSubset;
6361 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6362 table = (xmlAttributeTablePtr) dtd->attributes;
6363 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006364 }
6365 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006366 entities = (xmlEntitiesTablePtr) dtd->entities;
6367 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6368 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006369 }
6370 dtd = doc->extSubset;
6371 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6372 table = (xmlAttributeTablePtr) dtd->attributes;
6373 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006374 }
6375 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006376 entities = (xmlEntitiesTablePtr) dtd->entities;
6377 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6378 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006379 }
6380 return(ctxt->valid);
6381}
6382
6383/**
6384 * xmlValidateDocument:
6385 * @ctxt: the validation context
6386 * @doc: a document instance
6387 *
6388 * Try to validate the document instance
6389 *
6390 * basically it does the all the checks described by the XML Rec
6391 * i.e. validates the internal and external subset (if present)
6392 * and validate the document tree.
6393 *
6394 * returns 1 if valid or 0 otherwise
6395 */
6396
6397int
6398xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6399 int ret;
6400 xmlNodePtr root;
6401
Daniel Veillard2fd85422002-10-16 14:32:41 +00006402 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006403 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6404 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006405 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006406 }
Owen Taylor3473f882001-02-23 17:55:21 +00006407 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6408 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6409 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6410 doc->intSubset->SystemID);
6411 if (doc->extSubset == NULL) {
6412 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006413 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006414 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006415 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006416 } else {
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->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006420 }
6421 return(0);
6422 }
6423 }
6424
6425 if (doc->ids != NULL) {
6426 xmlFreeIDTable(doc->ids);
6427 doc->ids = NULL;
6428 }
6429 if (doc->refs != NULL) {
6430 xmlFreeRefTable(doc->refs);
6431 doc->refs = NULL;
6432 }
6433 ret = xmlValidateDtdFinal(ctxt, doc);
6434 if (!xmlValidateRoot(ctxt, doc)) return(0);
6435
6436 root = xmlDocGetRootElement(doc);
6437 ret &= xmlValidateElement(ctxt, doc, root);
6438 ret &= xmlValidateDocumentFinal(ctxt, doc);
6439 return(ret);
6440}
6441
Owen Taylor3473f882001-02-23 17:55:21 +00006442/************************************************************************
6443 * *
6444 * Routines for dynamic validation editing *
6445 * *
6446 ************************************************************************/
6447
6448/**
6449 * xmlValidGetPotentialChildren:
6450 * @ctree: an element content tree
6451 * @list: an array to store the list of child names
6452 * @len: a pointer to the number of element in the list
6453 * @max: the size of the array
6454 *
6455 * Build/extend a list of potential children allowed by the content tree
6456 *
6457 * returns the number of element in the list, or -1 in case of error.
6458 */
6459
6460int
6461xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6462 int *len, int max) {
6463 int i;
6464
6465 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6466 return(-1);
6467 if (*len >= max) return(*len);
6468
6469 switch (ctree->type) {
6470 case XML_ELEMENT_CONTENT_PCDATA:
6471 for (i = 0; i < *len;i++)
6472 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6473 list[(*len)++] = BAD_CAST "#PCDATA";
6474 break;
6475 case XML_ELEMENT_CONTENT_ELEMENT:
6476 for (i = 0; i < *len;i++)
6477 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6478 list[(*len)++] = ctree->name;
6479 break;
6480 case XML_ELEMENT_CONTENT_SEQ:
6481 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6482 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6483 break;
6484 case XML_ELEMENT_CONTENT_OR:
6485 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6486 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6487 break;
6488 }
6489
6490 return(*len);
6491}
6492
6493/**
6494 * xmlValidGetValidElements:
6495 * @prev: an element to insert after
6496 * @next: an element to insert next
6497 * @list: an array to store the list of child names
6498 * @max: the size of the array
6499 *
6500 * This function returns the list of authorized children to insert
6501 * within an existing tree while respecting the validity constraints
6502 * forced by the Dtd. The insertion point is defined using @prev and
6503 * @next in the following ways:
6504 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6505 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6506 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6507 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6508 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6509 *
6510 * pointers to the element names are inserted at the beginning of the array
6511 * and do not need to be freed.
6512 *
6513 * returns the number of element in the list, or -1 in case of error. If
6514 * the function returns the value @max the caller is invited to grow the
6515 * receiving array and retry.
6516 */
6517
6518int
6519xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
6520 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006521 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006522 int nb_valid_elements = 0;
6523 const xmlChar *elements[256];
6524 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006525 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006526
6527 xmlNode *ref_node;
6528 xmlNode *parent;
6529 xmlNode *test_node;
6530
6531 xmlNode *prev_next;
6532 xmlNode *next_prev;
6533 xmlNode *parent_childs;
6534 xmlNode *parent_last;
6535
6536 xmlElement *element_desc;
6537
Daniel Veillardbb4e46d2002-03-10 16:49:08 +00006538 memset(&vctxt, 0, sizeof (xmlValidCtxt));
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006539
Owen Taylor3473f882001-02-23 17:55:21 +00006540 if (prev == NULL && next == NULL)
6541 return(-1);
6542
6543 if (list == NULL) return(-1);
6544 if (max <= 0) return(-1);
6545
6546 nb_valid_elements = 0;
6547 ref_node = prev ? prev : next;
6548 parent = ref_node->parent;
6549
6550 /*
6551 * Retrieves the parent element declaration
6552 */
6553 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6554 parent->name);
6555 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6556 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6557 parent->name);
6558 if (element_desc == NULL) return(-1);
6559
6560 /*
6561 * Do a backup of the current tree structure
6562 */
6563 prev_next = prev ? prev->next : NULL;
6564 next_prev = next ? next->prev : NULL;
6565 parent_childs = parent->children;
6566 parent_last = parent->last;
6567
6568 /*
6569 * Creates a dummy node and insert it into the tree
6570 */
6571 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
6572 test_node->doc = ref_node->doc;
6573 test_node->parent = parent;
6574 test_node->prev = prev;
6575 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006576 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006577
6578 if (prev) prev->next = test_node;
6579 else parent->children = test_node;
6580
6581 if (next) next->prev = test_node;
6582 else parent->last = test_node;
6583
6584 /*
6585 * Insert each potential child node and check if the parent is
6586 * still valid
6587 */
6588 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6589 elements, &nb_elements, 256);
6590
6591 for (i = 0;i < nb_elements;i++) {
6592 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006593 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006594 int j;
6595
6596 for (j = 0; j < nb_valid_elements;j++)
6597 if (xmlStrEqual(elements[i], list[j])) break;
6598 list[nb_valid_elements++] = elements[i];
6599 if (nb_valid_elements >= max) break;
6600 }
6601 }
6602
6603 /*
6604 * Restore the tree structure
6605 */
6606 if (prev) prev->next = prev_next;
6607 if (next) next->prev = next_prev;
6608 parent->children = parent_childs;
6609 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006610
6611 /*
6612 * Free up the dummy node
6613 */
6614 test_node->name = name;
6615 xmlFreeNode(test_node);
6616
Owen Taylor3473f882001-02-23 17:55:21 +00006617 return(nb_valid_elements);
6618}
Daniel Veillard4432df22003-09-28 18:58:27 +00006619#endif /* LIBXML_VALID_ENABLED */
6620