blob: 6460334d7838c7b1456e19035118d7b1dad0b682 [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);
Daniel Veillarde62d36c2001-05-15 08:53:16 +000030/* #define DEBUG_VALID_ALGO */
Daniel Veillard5acfd6b2002-09-18 16:29:02 +000031/* #define DEBUG_REGEXP_ALGO */
Daniel Veillarde62d36c2001-05-15 08:53:16 +000032
Daniel Veillarda646cfd2002-09-17 21:50:03 +000033#define TODO \
34 xmlGenericError(xmlGenericErrorContext, \
35 "Unimplemented block at %s:%d\n", \
36 __FILE__, __LINE__);
Owen Taylor3473f882001-02-23 17:55:21 +000037
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000038/************************************************************************
39 * *
40 * Error handling routines *
41 * *
42 ************************************************************************/
43
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000044/**
Daniel Veillardce9457f2003-10-05 21:33:18 +000045 * xmlVErrMemory:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000046 * @ctxt: an XML validation parser context
47 * @extra: extra informations
48 *
49 * Handle an out of memory error
50 */
51static void
Daniel Veillardce9457f2003-10-05 21:33:18 +000052xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000053{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000054 xmlGenericErrorFunc channel = NULL;
55 xmlParserCtxtPtr pctxt = NULL;
56 void *data = NULL;
57
58 if (ctxt != NULL) {
59 channel = ctxt->error;
60 data = ctxt->userData;
61 pctxt = ctxt->userData;
62 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000063 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000064 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000065 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000066 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
67 "Memory allocation failed : %s\n", extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000068 else
Daniel Veillard73000572003-10-11 11:26:42 +000069 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000070 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000071 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
72 "Memory allocation failed\n");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000073}
74
75/**
76 * xmlErrValid:
77 * @ctxt: an XML validation parser context
Daniel Veillardbb5abab2003-10-03 22:21:51 +000078 * @error: the error number
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000079 * @extra: extra informations
80 *
81 * Handle a validation error
82 */
83static void
Daniel Veillardf88d8cf2003-12-08 10:25:02 +000084xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000085 const char *msg, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000086{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000087 xmlGenericErrorFunc channel = NULL;
88 xmlParserCtxtPtr pctxt = NULL;
89 void *data = NULL;
90
91 if (ctxt != NULL) {
92 channel = ctxt->error;
93 data = ctxt->userData;
94 pctxt = ctxt->userData;
95 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000096 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000097 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000098 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000099 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
100 msg, extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000101 else
Daniel Veillard73000572003-10-11 11:26:42 +0000102 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000103 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000104 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
105 msg);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000106}
107
Daniel Veillardf54cd532004-02-25 11:52:31 +0000108#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
109/**
110 * xmlErrValidNode:
111 * @ctxt: an XML validation parser context
112 * @node: the node raising the error
113 * @error: the error number
114 * @str1: extra informations
115 * @str2: extra informations
116 * @str3: extra informations
117 *
118 * Handle a validation error, provide contextual informations
119 */
120static void
121xmlErrValidNode(xmlValidCtxtPtr ctxt,
122 xmlNodePtr node, xmlParserErrors error,
123 const char *msg, const xmlChar * str1,
124 const xmlChar * str2, const xmlChar * str3)
125{
126 xmlStructuredErrorFunc schannel = NULL;
127 xmlGenericErrorFunc channel = NULL;
128 xmlParserCtxtPtr pctxt = NULL;
129 void *data = NULL;
130
131 if (ctxt != NULL) {
132 channel = ctxt->error;
133 data = ctxt->userData;
134 pctxt = ctxt->userData;
135 }
136 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
137 XML_ERR_ERROR, NULL, 0,
138 (const char *) str1,
139 (const char *) str1,
140 (const char *) str3, 0, 0, msg, str1, str2, str3);
141}
142#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
143
Daniel Veillardd61e8fb2003-10-19 21:59:17 +0000144#ifdef LIBXML_VALID_ENABLED
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000145/**
146 * xmlErrValidNodeNr:
147 * @ctxt: an XML validation parser context
148 * @node: the node raising the error
149 * @error: the error number
150 * @str1: extra informations
151 * @int2: extra informations
152 * @str3: extra informations
153 *
154 * Handle a validation error, provide contextual informations
155 */
156static void
Daniel Veillard72b9e292003-10-28 15:44:17 +0000157xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000158 xmlNodePtr node, xmlParserErrors error,
159 const char *msg, const xmlChar * str1,
160 int int2, const xmlChar * str3)
161{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000162 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000163 xmlGenericErrorFunc channel = NULL;
164 xmlParserCtxtPtr pctxt = NULL;
165 void *data = NULL;
166
167 if (ctxt != NULL) {
168 channel = ctxt->error;
169 data = ctxt->userData;
170 pctxt = ctxt->userData;
171 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000172 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000173 XML_ERR_ERROR, NULL, 0,
174 (const char *) str1,
175 (const char *) str3,
176 NULL, int2, 0, msg, str1, int2, str3);
177}
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000178
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000179/**
180 * xmlErrValidWarning:
181 * @ctxt: an XML validation parser context
182 * @node: the node raising the error
183 * @error: the error number
William M. Brackedb65a72004-02-06 07:36:04 +0000184 * @str1: extra information
185 * @str2: extra information
186 * @str3: extra information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000187 *
William M. Brackedb65a72004-02-06 07:36:04 +0000188 * Handle a validation error, provide contextual information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000189 */
190static void
William M. Brackedb65a72004-02-06 07:36:04 +0000191xmlErrValidWarning(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000192 xmlNodePtr node, xmlParserErrors error,
193 const char *msg, const xmlChar * str1,
194 const xmlChar * str2, const xmlChar * str3)
195{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000196 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000197 xmlGenericErrorFunc channel = NULL;
198 xmlParserCtxtPtr pctxt = NULL;
199 void *data = NULL;
200
201 if (ctxt != NULL) {
202 channel = ctxt->error;
203 data = ctxt->userData;
204 pctxt = ctxt->userData;
205 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000206 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, 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:
William M. Brack8b0cbb02004-04-17 13:31:06 +0000664 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
665 ctxt->state, NULL);
666 xmlAutomataNewTransition(ctxt->am,
667 ctxt->state, ctxt->state, fullname, 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
William M. Brackedb65a72004-02-06 07:36:04 +00001223xmlAddElementDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001224 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/**
William M. Brack9e660592003-10-20 14:56:06 +00001535 * xmlDumpElementDeclScan:
1536 * @elem: An element table
1537 * @buf: the XML buffer output
1538 *
1539 * This routine is used by the hash scan function. It just reverses
1540 * the arguments.
1541 */
1542static void
1543xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1544 xmlDumpElementDecl(buf, elem);
1545}
1546
1547/**
Owen Taylor3473f882001-02-23 17:55:21 +00001548 * xmlDumpElementTable:
1549 * @buf: the XML buffer output
1550 * @table: An element table
1551 *
1552 * This will dump the content of the element table as an XML DTD definition
1553 */
1554void
1555xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00001556 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001557}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001558#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001559
1560/**
1561 * xmlCreateEnumeration:
1562 * @name: the enumeration name or NULL
1563 *
1564 * create and initialize an enumeration attribute node.
1565 *
1566 * Returns the xmlEnumerationPtr just created or NULL in case
1567 * of error.
1568 */
1569xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001570xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001571 xmlEnumerationPtr ret;
1572
1573 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1574 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001575 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001576 return(NULL);
1577 }
1578 memset(ret, 0, sizeof(xmlEnumeration));
1579
1580 if (name != NULL)
1581 ret->name = xmlStrdup(name);
1582 return(ret);
1583}
1584
1585/**
1586 * xmlFreeEnumeration:
1587 * @cur: the tree to free.
1588 *
1589 * free an enumeration attribute node (recursive).
1590 */
1591void
1592xmlFreeEnumeration(xmlEnumerationPtr cur) {
1593 if (cur == NULL) return;
1594
1595 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1596
1597 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001598 xmlFree(cur);
1599}
1600
Daniel Veillard652327a2003-09-29 18:02:38 +00001601#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001602/**
1603 * xmlCopyEnumeration:
1604 * @cur: the tree to copy.
1605 *
1606 * Copy an enumeration attribute node (recursive).
1607 *
1608 * Returns the xmlEnumerationPtr just created or NULL in case
1609 * of error.
1610 */
1611xmlEnumerationPtr
1612xmlCopyEnumeration(xmlEnumerationPtr cur) {
1613 xmlEnumerationPtr ret;
1614
1615 if (cur == NULL) return(NULL);
1616 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1617
1618 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1619 else ret->next = NULL;
1620
1621 return(ret);
1622}
Daniel Veillard652327a2003-09-29 18:02:38 +00001623#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001624
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001625#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001626/**
1627 * xmlDumpEnumeration:
1628 * @buf: the XML buffer output
1629 * @enum: An enumeration
1630 *
1631 * This will dump the content of the enumeration
1632 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001633static void
Owen Taylor3473f882001-02-23 17:55:21 +00001634xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1635 if (cur == NULL) return;
1636
1637 xmlBufferWriteCHAR(buf, cur->name);
1638 if (cur->next == NULL)
1639 xmlBufferWriteChar(buf, ")");
1640 else {
1641 xmlBufferWriteChar(buf, " | ");
1642 xmlDumpEnumeration(buf, cur->next);
1643 }
1644}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001645#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001646
1647/**
1648 * xmlCreateAttributeTable:
1649 *
1650 * create and initialize an empty attribute hash table.
1651 *
1652 * Returns the xmlAttributeTablePtr just created or NULL in case
1653 * of error.
1654 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001655static xmlAttributeTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001656xmlCreateAttributeTable(void) {
1657 return(xmlHashCreate(0));
1658}
1659
Daniel Veillard4432df22003-09-28 18:58:27 +00001660#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001661/**
1662 * xmlScanAttributeDeclCallback:
1663 * @attr: the attribute decl
1664 * @list: the list to update
1665 *
1666 * Callback called by xmlScanAttributeDecl when a new attribute
1667 * has to be entered in the list.
1668 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001669static void
Owen Taylor3473f882001-02-23 17:55:21 +00001670xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001671 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001672 attr->nexth = *list;
1673 *list = attr;
1674}
1675
1676/**
1677 * xmlScanAttributeDecl:
1678 * @dtd: pointer to the DTD
1679 * @elem: the element name
1680 *
1681 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001682 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001683 *
1684 * Returns the pointer to the first attribute decl in the chain,
1685 * possibly NULL.
1686 */
1687xmlAttributePtr
1688xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1689 xmlAttributePtr ret = NULL;
1690 xmlAttributeTablePtr table;
1691
1692 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001693 return(NULL);
1694 }
1695 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001696 return(NULL);
1697 }
1698 table = (xmlAttributeTablePtr) dtd->attributes;
1699 if (table == NULL)
1700 return(NULL);
1701
1702 /* WRONG !!! */
1703 xmlHashScan3(table, NULL, NULL, elem,
1704 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1705 return(ret);
1706}
1707
1708/**
1709 * xmlScanIDAttributeDecl:
1710 * @ctxt: the validation context
1711 * @elem: the element name
1712 *
1713 * Verify that the element don't have too many ID attributes
1714 * declared.
1715 *
1716 * Returns the number of ID attributes found.
1717 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001718static int
Owen Taylor3473f882001-02-23 17:55:21 +00001719xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1720 xmlAttributePtr cur;
1721 int ret = 0;
1722
1723 if (elem == NULL) return(0);
1724 cur = elem->attributes;
1725 while (cur != NULL) {
1726 if (cur->atype == XML_ATTRIBUTE_ID) {
1727 ret ++;
1728 if (ret > 1)
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001729 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001730 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001731 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001732 }
1733 cur = cur->nexth;
1734 }
1735 return(ret);
1736}
Daniel Veillard4432df22003-09-28 18:58:27 +00001737#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001738
1739/**
1740 * xmlFreeAttribute:
1741 * @elem: An attribute
1742 *
1743 * Deallocate the memory used by an attribute definition
1744 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001745static void
Owen Taylor3473f882001-02-23 17:55:21 +00001746xmlFreeAttribute(xmlAttributePtr attr) {
1747 if (attr == NULL) return;
1748 xmlUnlinkNode((xmlNodePtr) attr);
1749 if (attr->tree != NULL)
1750 xmlFreeEnumeration(attr->tree);
1751 if (attr->elem != NULL)
1752 xmlFree((xmlChar *) attr->elem);
1753 if (attr->name != NULL)
1754 xmlFree((xmlChar *) attr->name);
1755 if (attr->defaultValue != NULL)
1756 xmlFree((xmlChar *) attr->defaultValue);
1757 if (attr->prefix != NULL)
1758 xmlFree((xmlChar *) attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001759 xmlFree(attr);
1760}
1761
1762
1763/**
1764 * xmlAddAttributeDecl:
1765 * @ctxt: the validation context
1766 * @dtd: pointer to the DTD
1767 * @elem: the element name
1768 * @name: the attribute name
1769 * @ns: the attribute namespace prefix
1770 * @type: the attribute type
1771 * @def: the attribute default type
1772 * @defaultValue: the attribute default value
1773 * @tree: if it's an enumeration, the associated list
1774 *
1775 * Register a new attribute declaration
1776 * Note that @tree becomes the ownership of the DTD
1777 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001778 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001779 */
1780xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001781xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001782 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001783 const xmlChar *name, const xmlChar *ns,
1784 xmlAttributeType type, xmlAttributeDefault def,
1785 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1786 xmlAttributePtr ret;
1787 xmlAttributeTablePtr table;
1788 xmlElementPtr elemDef;
1789
1790 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001791 xmlFreeEnumeration(tree);
1792 return(NULL);
1793 }
1794 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001795 xmlFreeEnumeration(tree);
1796 return(NULL);
1797 }
1798 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001799 xmlFreeEnumeration(tree);
1800 return(NULL);
1801 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001802
Daniel Veillard4432df22003-09-28 18:58:27 +00001803#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001804 /*
1805 * Check the type and possibly the default value.
1806 */
1807 switch (type) {
1808 case XML_ATTRIBUTE_CDATA:
1809 break;
1810 case XML_ATTRIBUTE_ID:
1811 break;
1812 case XML_ATTRIBUTE_IDREF:
1813 break;
1814 case XML_ATTRIBUTE_IDREFS:
1815 break;
1816 case XML_ATTRIBUTE_ENTITY:
1817 break;
1818 case XML_ATTRIBUTE_ENTITIES:
1819 break;
1820 case XML_ATTRIBUTE_NMTOKEN:
1821 break;
1822 case XML_ATTRIBUTE_NMTOKENS:
1823 break;
1824 case XML_ATTRIBUTE_ENUMERATION:
1825 break;
1826 case XML_ATTRIBUTE_NOTATION:
1827 break;
1828 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001829 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1830 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1831 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001832 xmlFreeEnumeration(tree);
1833 return(NULL);
1834 }
1835 if ((defaultValue != NULL) &&
1836 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001837 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1838 "Attribute %s of %s: invalid default value\n",
1839 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00001840 defaultValue = NULL;
Daniel Veillardd01fd3e2002-02-18 22:27:47 +00001841 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001842 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001843#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001844
1845 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001846 * Check first that an attribute defined in the external subset wasn't
1847 * already defined in the internal subset
1848 */
1849 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1850 (dtd->doc->intSubset != NULL) &&
1851 (dtd->doc->intSubset->attributes != NULL)) {
1852 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1853 if (ret != NULL)
1854 return(NULL);
1855 }
1856
1857 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001858 * Create the Attribute table if needed.
1859 */
1860 table = (xmlAttributeTablePtr) dtd->attributes;
1861 if (table == NULL) {
1862 table = xmlCreateAttributeTable();
1863 dtd->attributes = (void *) table;
1864 }
1865 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001866 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001867 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001868 return(NULL);
1869 }
1870
1871
1872 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1873 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001874 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001875 return(NULL);
1876 }
1877 memset(ret, 0, sizeof(xmlAttribute));
1878 ret->type = XML_ATTRIBUTE_DECL;
1879
1880 /*
1881 * fill the structure.
1882 */
1883 ret->atype = type;
1884 ret->name = xmlStrdup(name);
1885 ret->prefix = xmlStrdup(ns);
1886 ret->elem = xmlStrdup(elem);
1887 ret->def = def;
1888 ret->tree = tree;
1889 if (defaultValue != NULL)
1890 ret->defaultValue = xmlStrdup(defaultValue);
1891
1892 /*
1893 * Validity Check:
1894 * Search the DTD for previous declarations of the ATTLIST
1895 */
1896 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001897#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001898 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001899 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00001900 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001901 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00001902 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001903 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001904#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001905 xmlFreeAttribute(ret);
1906 return(NULL);
1907 }
1908
1909 /*
1910 * Validity Check:
1911 * Multiple ID per element
1912 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001913 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001914 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00001915
Daniel Veillard4432df22003-09-28 18:58:27 +00001916#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001917 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00001918 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001919 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00001920 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001921 elem, name, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00001922 ctxt->valid = 0;
1923 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001924#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00001925
Daniel Veillard48da9102001-08-07 01:10:10 +00001926 /*
1927 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001928 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00001929 */
1930 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1931 ((ret->prefix != NULL &&
1932 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1933 ret->nexth = elemDef->attributes;
1934 elemDef->attributes = ret;
1935 } else {
1936 xmlAttributePtr tmp = elemDef->attributes;
1937
1938 while ((tmp != NULL) &&
1939 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1940 ((ret->prefix != NULL &&
1941 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1942 if (tmp->nexth == NULL)
1943 break;
1944 tmp = tmp->nexth;
1945 }
1946 if (tmp != NULL) {
1947 ret->nexth = tmp->nexth;
1948 tmp->nexth = ret;
1949 } else {
1950 ret->nexth = elemDef->attributes;
1951 elemDef->attributes = ret;
1952 }
1953 }
Owen Taylor3473f882001-02-23 17:55:21 +00001954 }
1955
1956 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001957 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001958 */
1959 ret->parent = dtd;
1960 ret->doc = dtd->doc;
1961 if (dtd->last == NULL) {
1962 dtd->children = dtd->last = (xmlNodePtr) ret;
1963 } else {
1964 dtd->last->next = (xmlNodePtr) ret;
1965 ret->prev = dtd->last;
1966 dtd->last = (xmlNodePtr) ret;
1967 }
1968 return(ret);
1969}
1970
1971/**
1972 * xmlFreeAttributeTable:
1973 * @table: An attribute table
1974 *
1975 * Deallocate the memory used by an entities hash table.
1976 */
1977void
1978xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1979 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
1980}
1981
Daniel Veillard652327a2003-09-29 18:02:38 +00001982#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001983/**
1984 * xmlCopyAttribute:
1985 * @attr: An attribute
1986 *
1987 * Build a copy of an attribute.
1988 *
1989 * Returns the new xmlAttributePtr or NULL in case of error.
1990 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001991static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001992xmlCopyAttribute(xmlAttributePtr attr) {
1993 xmlAttributePtr cur;
1994
1995 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1996 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001997 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001998 return(NULL);
1999 }
2000 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00002001 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00002002 cur->atype = attr->atype;
2003 cur->def = attr->def;
2004 cur->tree = xmlCopyEnumeration(attr->tree);
2005 if (attr->elem != NULL)
2006 cur->elem = xmlStrdup(attr->elem);
2007 if (attr->name != NULL)
2008 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002009 if (attr->prefix != NULL)
2010 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002011 if (attr->defaultValue != NULL)
2012 cur->defaultValue = xmlStrdup(attr->defaultValue);
2013 return(cur);
2014}
2015
2016/**
2017 * xmlCopyAttributeTable:
2018 * @table: An attribute table
2019 *
2020 * Build a copy of an attribute table.
2021 *
2022 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2023 */
2024xmlAttributeTablePtr
2025xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2026 return((xmlAttributeTablePtr) xmlHashCopy(table,
2027 (xmlHashCopier) xmlCopyAttribute));
2028}
Daniel Veillard652327a2003-09-29 18:02:38 +00002029#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002030
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002031#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002032/**
2033 * xmlDumpAttributeDecl:
2034 * @buf: the XML buffer output
2035 * @attr: An attribute declaration
2036 *
2037 * This will dump the content of the attribute declaration as an XML
2038 * DTD definition
2039 */
2040void
2041xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2042 xmlBufferWriteChar(buf, "<!ATTLIST ");
2043 xmlBufferWriteCHAR(buf, attr->elem);
2044 xmlBufferWriteChar(buf, " ");
2045 if (attr->prefix != NULL) {
2046 xmlBufferWriteCHAR(buf, attr->prefix);
2047 xmlBufferWriteChar(buf, ":");
2048 }
2049 xmlBufferWriteCHAR(buf, attr->name);
2050 switch (attr->atype) {
2051 case XML_ATTRIBUTE_CDATA:
2052 xmlBufferWriteChar(buf, " CDATA");
2053 break;
2054 case XML_ATTRIBUTE_ID:
2055 xmlBufferWriteChar(buf, " ID");
2056 break;
2057 case XML_ATTRIBUTE_IDREF:
2058 xmlBufferWriteChar(buf, " IDREF");
2059 break;
2060 case XML_ATTRIBUTE_IDREFS:
2061 xmlBufferWriteChar(buf, " IDREFS");
2062 break;
2063 case XML_ATTRIBUTE_ENTITY:
2064 xmlBufferWriteChar(buf, " ENTITY");
2065 break;
2066 case XML_ATTRIBUTE_ENTITIES:
2067 xmlBufferWriteChar(buf, " ENTITIES");
2068 break;
2069 case XML_ATTRIBUTE_NMTOKEN:
2070 xmlBufferWriteChar(buf, " NMTOKEN");
2071 break;
2072 case XML_ATTRIBUTE_NMTOKENS:
2073 xmlBufferWriteChar(buf, " NMTOKENS");
2074 break;
2075 case XML_ATTRIBUTE_ENUMERATION:
2076 xmlBufferWriteChar(buf, " (");
2077 xmlDumpEnumeration(buf, attr->tree);
2078 break;
2079 case XML_ATTRIBUTE_NOTATION:
2080 xmlBufferWriteChar(buf, " NOTATION (");
2081 xmlDumpEnumeration(buf, attr->tree);
2082 break;
2083 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002084 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2085 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2086 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002087 }
2088 switch (attr->def) {
2089 case XML_ATTRIBUTE_NONE:
2090 break;
2091 case XML_ATTRIBUTE_REQUIRED:
2092 xmlBufferWriteChar(buf, " #REQUIRED");
2093 break;
2094 case XML_ATTRIBUTE_IMPLIED:
2095 xmlBufferWriteChar(buf, " #IMPLIED");
2096 break;
2097 case XML_ATTRIBUTE_FIXED:
2098 xmlBufferWriteChar(buf, " #FIXED");
2099 break;
2100 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002101 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2102 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2103 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002104 }
2105 if (attr->defaultValue != NULL) {
2106 xmlBufferWriteChar(buf, " ");
2107 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2108 }
2109 xmlBufferWriteChar(buf, ">\n");
2110}
2111
2112/**
William M. Brack9e660592003-10-20 14:56:06 +00002113 * xmlDumpAttributeDeclScan:
2114 * @attr: An attribute declaration
2115 * @buf: the XML buffer output
2116 *
2117 * This is used with the hash scan function - just reverses arguments
2118 */
2119static void
2120xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2121 xmlDumpAttributeDecl(buf, attr);
2122}
2123
2124/**
Owen Taylor3473f882001-02-23 17:55:21 +00002125 * xmlDumpAttributeTable:
2126 * @buf: the XML buffer output
2127 * @table: An attribute table
2128 *
2129 * This will dump the content of the attribute table as an XML DTD definition
2130 */
2131void
2132xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002133 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002134}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002135#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002136
2137/************************************************************************
2138 * *
2139 * NOTATIONs *
2140 * *
2141 ************************************************************************/
2142/**
2143 * xmlCreateNotationTable:
2144 *
2145 * create and initialize an empty notation hash table.
2146 *
2147 * Returns the xmlNotationTablePtr just created or NULL in case
2148 * of error.
2149 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002150static xmlNotationTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002151xmlCreateNotationTable(void) {
2152 return(xmlHashCreate(0));
2153}
2154
2155/**
2156 * xmlFreeNotation:
2157 * @not: A notation
2158 *
2159 * Deallocate the memory used by an notation definition
2160 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002161static void
Owen Taylor3473f882001-02-23 17:55:21 +00002162xmlFreeNotation(xmlNotationPtr nota) {
2163 if (nota == NULL) return;
2164 if (nota->name != NULL)
2165 xmlFree((xmlChar *) nota->name);
2166 if (nota->PublicID != NULL)
2167 xmlFree((xmlChar *) nota->PublicID);
2168 if (nota->SystemID != NULL)
2169 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002170 xmlFree(nota);
2171}
2172
2173
2174/**
2175 * xmlAddNotationDecl:
2176 * @dtd: pointer to the DTD
2177 * @ctxt: the validation context
2178 * @name: the entity name
2179 * @PublicID: the public identifier or NULL
2180 * @SystemID: the system identifier or NULL
2181 *
2182 * Register a new notation declaration
2183 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002184 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002185 */
2186xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002187xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002188 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002189 const xmlChar *PublicID, const xmlChar *SystemID) {
2190 xmlNotationPtr ret;
2191 xmlNotationTablePtr table;
2192
2193 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002194 return(NULL);
2195 }
2196 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002197 return(NULL);
2198 }
2199 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002200 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002201 }
2202
2203 /*
2204 * Create the Notation table if needed.
2205 */
2206 table = (xmlNotationTablePtr) dtd->notations;
2207 if (table == NULL)
2208 dtd->notations = table = xmlCreateNotationTable();
2209 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002210 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002211 "xmlAddNotationDecl: Table creation failed!\n");
2212 return(NULL);
2213 }
2214
2215 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2216 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002217 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002218 return(NULL);
2219 }
2220 memset(ret, 0, sizeof(xmlNotation));
2221
2222 /*
2223 * fill the structure.
2224 */
2225 ret->name = xmlStrdup(name);
2226 if (SystemID != NULL)
2227 ret->SystemID = xmlStrdup(SystemID);
2228 if (PublicID != NULL)
2229 ret->PublicID = xmlStrdup(PublicID);
2230
2231 /*
2232 * Validity Check:
2233 * Check the DTD for previous declarations of the ATTLIST
2234 */
2235 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002236#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002237 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2238 "xmlAddNotationDecl: %s already defined\n",
2239 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002240#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002241 xmlFreeNotation(ret);
2242 return(NULL);
2243 }
2244 return(ret);
2245}
2246
2247/**
2248 * xmlFreeNotationTable:
2249 * @table: An notation table
2250 *
2251 * Deallocate the memory used by an entities hash table.
2252 */
2253void
2254xmlFreeNotationTable(xmlNotationTablePtr table) {
2255 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2256}
2257
Daniel Veillard652327a2003-09-29 18:02:38 +00002258#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002259/**
2260 * xmlCopyNotation:
2261 * @nota: A notation
2262 *
2263 * Build a copy of a notation.
2264 *
2265 * Returns the new xmlNotationPtr or NULL in case of error.
2266 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002267static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002268xmlCopyNotation(xmlNotationPtr nota) {
2269 xmlNotationPtr cur;
2270
2271 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2272 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002273 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002274 return(NULL);
2275 }
2276 if (nota->name != NULL)
2277 cur->name = xmlStrdup(nota->name);
2278 else
2279 cur->name = NULL;
2280 if (nota->PublicID != NULL)
2281 cur->PublicID = xmlStrdup(nota->PublicID);
2282 else
2283 cur->PublicID = NULL;
2284 if (nota->SystemID != NULL)
2285 cur->SystemID = xmlStrdup(nota->SystemID);
2286 else
2287 cur->SystemID = NULL;
2288 return(cur);
2289}
2290
2291/**
2292 * xmlCopyNotationTable:
2293 * @table: A notation table
2294 *
2295 * Build a copy of a notation table.
2296 *
2297 * Returns the new xmlNotationTablePtr or NULL in case of error.
2298 */
2299xmlNotationTablePtr
2300xmlCopyNotationTable(xmlNotationTablePtr table) {
2301 return((xmlNotationTablePtr) xmlHashCopy(table,
2302 (xmlHashCopier) xmlCopyNotation));
2303}
Daniel Veillard652327a2003-09-29 18:02:38 +00002304#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002305
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002306#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002307/**
2308 * xmlDumpNotationDecl:
2309 * @buf: the XML buffer output
2310 * @nota: A notation declaration
2311 *
2312 * This will dump the content the notation declaration as an XML DTD definition
2313 */
2314void
2315xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2316 xmlBufferWriteChar(buf, "<!NOTATION ");
2317 xmlBufferWriteCHAR(buf, nota->name);
2318 if (nota->PublicID != NULL) {
2319 xmlBufferWriteChar(buf, " PUBLIC ");
2320 xmlBufferWriteQuotedString(buf, nota->PublicID);
2321 if (nota->SystemID != NULL) {
2322 xmlBufferWriteChar(buf, " ");
2323 xmlBufferWriteCHAR(buf, nota->SystemID);
2324 }
2325 } else {
2326 xmlBufferWriteChar(buf, " SYSTEM ");
2327 xmlBufferWriteCHAR(buf, nota->SystemID);
2328 }
2329 xmlBufferWriteChar(buf, " >\n");
2330}
2331
2332/**
William M. Brack9e660592003-10-20 14:56:06 +00002333 * xmlDumpNotationDeclScan:
2334 * @nota: A notation declaration
2335 * @buf: the XML buffer output
2336 *
2337 * This is called with the hash scan function, and just reverses args
2338 */
2339static void
2340xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2341 xmlDumpNotationDecl(buf, nota);
2342}
2343
2344/**
Owen Taylor3473f882001-02-23 17:55:21 +00002345 * xmlDumpNotationTable:
2346 * @buf: the XML buffer output
2347 * @table: A notation table
2348 *
2349 * This will dump the content of the notation table as an XML DTD definition
2350 */
2351void
2352xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002353 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002354}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002355#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002356
2357/************************************************************************
2358 * *
2359 * IDs *
2360 * *
2361 ************************************************************************/
2362/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002363 * DICT_FREE:
2364 * @str: a string
2365 *
2366 * Free a string if it is not owned by the "dict" dictionnary in the
2367 * current scope
2368 */
2369#define DICT_FREE(str) \
2370 if ((str) && ((!dict) || \
2371 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2372 xmlFree((char *)(str));
2373
2374/**
Owen Taylor3473f882001-02-23 17:55:21 +00002375 * xmlCreateIDTable:
2376 *
2377 * create and initialize an empty id hash table.
2378 *
2379 * Returns the xmlIDTablePtr just created or NULL in case
2380 * of error.
2381 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002382static xmlIDTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002383xmlCreateIDTable(void) {
2384 return(xmlHashCreate(0));
2385}
2386
2387/**
2388 * xmlFreeID:
2389 * @not: A id
2390 *
2391 * Deallocate the memory used by an id definition
2392 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002393static void
Owen Taylor3473f882001-02-23 17:55:21 +00002394xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002395 xmlDictPtr dict = NULL;
2396
Owen Taylor3473f882001-02-23 17:55:21 +00002397 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002398
2399 if (id->doc != NULL)
2400 dict = id->doc->dict;
2401
Owen Taylor3473f882001-02-23 17:55:21 +00002402 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002403 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002404 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002405 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002406 xmlFree(id);
2407}
2408
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002409
Owen Taylor3473f882001-02-23 17:55:21 +00002410/**
2411 * xmlAddID:
2412 * @ctxt: the validation context
2413 * @doc: pointer to the document
2414 * @value: the value name
2415 * @attr: the attribute holding the ID
2416 *
2417 * Register a new id declaration
2418 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002419 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002420 */
2421xmlIDPtr
2422xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2423 xmlAttrPtr attr) {
2424 xmlIDPtr ret;
2425 xmlIDTablePtr table;
2426
2427 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002428 return(NULL);
2429 }
2430 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002431 return(NULL);
2432 }
2433 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002434 return(NULL);
2435 }
2436
2437 /*
2438 * Create the ID table if needed.
2439 */
2440 table = (xmlIDTablePtr) doc->ids;
2441 if (table == NULL)
2442 doc->ids = table = xmlCreateIDTable();
2443 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002444 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002445 "xmlAddID: Table creation failed!\n");
2446 return(NULL);
2447 }
2448
2449 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2450 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002451 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002452 return(NULL);
2453 }
2454
2455 /*
2456 * fill the structure.
2457 */
2458 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002459 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002460 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2461 /*
2462 * Operating in streaming mode, attr is gonna disapear
2463 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002464 if (doc->dict != NULL)
2465 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2466 else
2467 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002468 ret->attr = NULL;
2469 } else {
2470 ret->attr = attr;
2471 ret->name = NULL;
2472 }
2473 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002474
2475 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002476#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002477 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002478 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002479 */
Daniel Veillardd3669b22004-02-25 12:34:55 +00002480 if ((ctxt != NULL) && (ctxt->error != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002481 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2482 "ID %s already defined\n",
2483 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002484 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002485#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002486 xmlFreeID(ret);
2487 return(NULL);
2488 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002489 if (attr != NULL)
2490 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002491 return(ret);
2492}
2493
2494/**
2495 * xmlFreeIDTable:
2496 * @table: An id table
2497 *
2498 * Deallocate the memory used by an ID hash table.
2499 */
2500void
2501xmlFreeIDTable(xmlIDTablePtr table) {
2502 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2503}
2504
2505/**
2506 * xmlIsID:
2507 * @doc: the document
2508 * @elem: the element carrying the attribute
2509 * @attr: the attribute
2510 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002511 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002512 * then this is done if DTD loading has been requested. In the case
2513 * of HTML documents parsed with the HTML parser, then ID detection is
2514 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002515 *
2516 * Returns 0 or 1 depending on the lookup result
2517 */
2518int
2519xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2520 if (doc == NULL) return(0);
2521 if (attr == NULL) return(0);
2522 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2523 return(0);
2524 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard9ba8e382003-10-28 21:31:45 +00002525 if (((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2526 (xmlStrEqual(BAD_CAST "name", attr->name))) &&
2527 ((elem != NULL) && (!xmlStrEqual(elem->name, BAD_CAST "input"))))
Owen Taylor3473f882001-02-23 17:55:21 +00002528 return(1);
2529 return(0);
2530 } else {
2531 xmlAttributePtr attrDecl;
2532
2533 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002534 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002535 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002536 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002537
2538 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002539 if (fullname == NULL)
2540 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002541 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2542 attr->name);
2543 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2544 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2545 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002546 if ((fullname != fn) && (fullname != elem->name))
2547 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002548 } else {
2549 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2550 attr->name);
2551 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2552 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2553 attr->name);
2554 }
Owen Taylor3473f882001-02-23 17:55:21 +00002555
2556 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2557 return(1);
2558 }
2559 return(0);
2560}
2561
2562/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002563 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002564 * @doc: the document
2565 * @attr: the attribute
2566 *
2567 * Remove the given attribute from the ID table maintained internally.
2568 *
2569 * Returns -1 if the lookup failed and 0 otherwise
2570 */
2571int
2572xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002573 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002574 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002575 xmlChar *ID;
2576
2577 if (doc == NULL) return(-1);
2578 if (attr == NULL) return(-1);
2579 table = (xmlIDTablePtr) doc->ids;
2580 if (table == NULL)
2581 return(-1);
2582
2583 if (attr == NULL)
2584 return(-1);
2585 ID = xmlNodeListGetString(doc, attr->children, 1);
2586 if (ID == NULL)
2587 return(-1);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002588 id = xmlHashLookup(table, ID);
2589 if (id == NULL || id->attr != attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002590 xmlFree(ID);
2591 return(-1);
2592 }
2593 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
2594 xmlFree(ID);
2595 return(0);
2596}
2597
2598/**
2599 * xmlGetID:
2600 * @doc: pointer to the document
2601 * @ID: the ID value
2602 *
2603 * Search the attribute declaring the given ID
2604 *
2605 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2606 */
2607xmlAttrPtr
2608xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2609 xmlIDTablePtr table;
2610 xmlIDPtr id;
2611
2612 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002613 return(NULL);
2614 }
2615
2616 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002617 return(NULL);
2618 }
2619
2620 table = (xmlIDTablePtr) doc->ids;
2621 if (table == NULL)
2622 return(NULL);
2623
2624 id = xmlHashLookup(table, ID);
2625 if (id == NULL)
2626 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002627 if (id->attr == NULL) {
2628 /*
2629 * We are operating on a stream, return a well known reference
2630 * since the attribute node doesn't exist anymore
2631 */
2632 return((xmlAttrPtr) doc);
2633 }
Owen Taylor3473f882001-02-23 17:55:21 +00002634 return(id->attr);
2635}
2636
2637/************************************************************************
2638 * *
2639 * Refs *
2640 * *
2641 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002642typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002643{
2644 xmlListPtr l;
2645 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002646} xmlRemoveMemo;
2647
2648typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2649
2650typedef struct xmlValidateMemo_t
2651{
2652 xmlValidCtxtPtr ctxt;
2653 const xmlChar *name;
2654} xmlValidateMemo;
2655
2656typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002657
2658/**
2659 * xmlCreateRefTable:
2660 *
2661 * create and initialize an empty ref hash table.
2662 *
2663 * Returns the xmlRefTablePtr just created or NULL in case
2664 * of error.
2665 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002666static xmlRefTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002667xmlCreateRefTable(void) {
2668 return(xmlHashCreate(0));
2669}
2670
2671/**
2672 * xmlFreeRef:
2673 * @lk: A list link
2674 *
2675 * Deallocate the memory used by a ref definition
2676 */
2677static void
2678xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002679 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2680 if (ref == NULL) return;
2681 if (ref->value != NULL)
2682 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002683 if (ref->name != NULL)
2684 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002685 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002686}
2687
2688/**
2689 * xmlFreeRefList:
2690 * @list_ref: A list of references.
2691 *
2692 * Deallocate the memory used by a list of references
2693 */
2694static void
2695xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002696 if (list_ref == NULL) return;
2697 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002698}
2699
2700/**
2701 * xmlWalkRemoveRef:
2702 * @data: Contents of current link
2703 * @user: Value supplied by the user
2704 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002705 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002706 */
2707static int
2708xmlWalkRemoveRef(const void *data, const void *user)
2709{
Daniel Veillard37721922001-05-04 15:21:12 +00002710 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2711 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2712 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002713
Daniel Veillard37721922001-05-04 15:21:12 +00002714 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2715 xmlListRemoveFirst(ref_list, (void *)data);
2716 return 0;
2717 }
2718 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002719}
2720
2721/**
Daniel Veillard770075b2004-02-25 10:44:30 +00002722 * xmlDummyCompare
2723 * @data0: Value supplied by the user
2724 * @data1: Value supplied by the user
2725 *
2726 * Do nothing, return 0. Used to create unordered lists.
2727 */
2728static int
Daniel Veillardf54cd532004-02-25 11:52:31 +00002729xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2730 const void *data1 ATTRIBUTE_UNUSED)
Daniel Veillard770075b2004-02-25 10:44:30 +00002731{
2732 return (0);
2733}
2734
2735/**
Owen Taylor3473f882001-02-23 17:55:21 +00002736 * xmlAddRef:
2737 * @ctxt: the validation context
2738 * @doc: pointer to the document
2739 * @value: the value name
2740 * @attr: the attribute holding the Ref
2741 *
2742 * Register a new ref declaration
2743 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002744 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002745 */
2746xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002747xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002748 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002749 xmlRefPtr ret;
2750 xmlRefTablePtr table;
2751 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002752
Daniel Veillard37721922001-05-04 15:21:12 +00002753 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002754 return(NULL);
2755 }
2756 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002757 return(NULL);
2758 }
2759 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002760 return(NULL);
2761 }
Owen Taylor3473f882001-02-23 17:55:21 +00002762
Daniel Veillard37721922001-05-04 15:21:12 +00002763 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002764 * Create the Ref table if needed.
2765 */
Daniel Veillard37721922001-05-04 15:21:12 +00002766 table = (xmlRefTablePtr) doc->refs;
2767 if (table == NULL)
2768 doc->refs = table = xmlCreateRefTable();
2769 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002770 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002771 "xmlAddRef: Table creation failed!\n");
2772 return(NULL);
2773 }
Owen Taylor3473f882001-02-23 17:55:21 +00002774
Daniel Veillard37721922001-05-04 15:21:12 +00002775 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2776 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002777 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002778 return(NULL);
2779 }
Owen Taylor3473f882001-02-23 17:55:21 +00002780
Daniel Veillard37721922001-05-04 15:21:12 +00002781 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002782 * fill the structure.
2783 */
Daniel Veillard37721922001-05-04 15:21:12 +00002784 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002785 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2786 /*
2787 * Operating in streaming mode, attr is gonna disapear
2788 */
2789 ret->name = xmlStrdup(attr->name);
2790 ret->attr = NULL;
2791 } else {
2792 ret->name = NULL;
2793 ret->attr = attr;
2794 }
2795 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002796
Daniel Veillard37721922001-05-04 15:21:12 +00002797 /* To add a reference :-
2798 * References are maintained as a list of references,
2799 * Lookup the entry, if no entry create new nodelist
2800 * Add the owning node to the NodeList
2801 * Return the ref
2802 */
Owen Taylor3473f882001-02-23 17:55:21 +00002803
Daniel Veillard37721922001-05-04 15:21:12 +00002804 if (NULL == (ref_list = xmlHashLookup(table, value))) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002805 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002806 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2807 "xmlAddRef: Reference list creation failed!\n",
2808 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002809 return(NULL);
2810 }
2811 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2812 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002813 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2814 "xmlAddRef: Reference list insertion failed!\n",
2815 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002816 return(NULL);
2817 }
2818 }
Daniel Veillard965983a2004-02-17 16:30:24 +00002819/* xmlListInsert(ref_list, ret); */
2820 xmlListAppend(ref_list, ret);
Daniel Veillard37721922001-05-04 15:21:12 +00002821 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002822}
2823
2824/**
2825 * xmlFreeRefTable:
2826 * @table: An ref table
2827 *
2828 * Deallocate the memory used by an Ref hash table.
2829 */
2830void
2831xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002832 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002833}
2834
2835/**
2836 * xmlIsRef:
2837 * @doc: the document
2838 * @elem: the element carrying the attribute
2839 * @attr: the attribute
2840 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002841 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00002842 * then this is simple, otherwise we use an heuristic: name Ref (upper
2843 * or lowercase).
2844 *
2845 * Returns 0 or 1 depending on the lookup result
2846 */
2847int
2848xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002849 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2850 return(0);
2851 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2852 /* TODO @@@ */
2853 return(0);
2854 } else {
2855 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00002856
Daniel Veillard37721922001-05-04 15:21:12 +00002857 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2858 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2859 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2860 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002861
Daniel Veillard37721922001-05-04 15:21:12 +00002862 if ((attrDecl != NULL) &&
2863 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2864 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2865 return(1);
2866 }
2867 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002868}
2869
2870/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002871 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00002872 * @doc: the document
2873 * @attr: the attribute
2874 *
2875 * Remove the given attribute from the Ref table maintained internally.
2876 *
2877 * Returns -1 if the lookup failed and 0 otherwise
2878 */
2879int
2880xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002881 xmlListPtr ref_list;
2882 xmlRefTablePtr table;
2883 xmlChar *ID;
2884 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00002885
Daniel Veillard37721922001-05-04 15:21:12 +00002886 if (doc == NULL) return(-1);
2887 if (attr == NULL) return(-1);
2888 table = (xmlRefTablePtr) doc->refs;
2889 if (table == NULL)
2890 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002891
Daniel Veillard37721922001-05-04 15:21:12 +00002892 if (attr == NULL)
2893 return(-1);
2894 ID = xmlNodeListGetString(doc, attr->children, 1);
2895 if (ID == NULL)
2896 return(-1);
2897 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00002898
Daniel Veillard37721922001-05-04 15:21:12 +00002899 if(ref_list == NULL) {
2900 xmlFree(ID);
2901 return (-1);
2902 }
2903 /* At this point, ref_list refers to a list of references which
2904 * have the same key as the supplied attr. Our list of references
2905 * is ordered by reference address and we don't have that information
2906 * here to use when removing. We'll have to walk the list and
2907 * check for a matching attribute, when we find one stop the walk
2908 * and remove the entry.
2909 * The list is ordered by reference, so that means we don't have the
2910 * key. Passing the list and the reference to the walker means we
2911 * will have enough data to be able to remove the entry.
2912 */
2913 target.l = ref_list;
2914 target.ap = attr;
2915
2916 /* Remove the supplied attr from our list */
2917 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00002918
Daniel Veillard37721922001-05-04 15:21:12 +00002919 /*If the list is empty then remove the list entry in the hash */
2920 if (xmlListEmpty(ref_list))
2921 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2922 xmlFreeRefList);
2923 xmlFree(ID);
2924 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002925}
2926
2927/**
2928 * xmlGetRefs:
2929 * @doc: pointer to the document
2930 * @ID: the ID value
2931 *
2932 * Find the set of references for the supplied ID.
2933 *
2934 * Returns NULL if not found, otherwise node set for the ID.
2935 */
2936xmlListPtr
2937xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00002938 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00002939
Daniel Veillard37721922001-05-04 15:21:12 +00002940 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002941 return(NULL);
2942 }
Owen Taylor3473f882001-02-23 17:55:21 +00002943
Daniel Veillard37721922001-05-04 15:21:12 +00002944 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002945 return(NULL);
2946 }
Owen Taylor3473f882001-02-23 17:55:21 +00002947
Daniel Veillard37721922001-05-04 15:21:12 +00002948 table = (xmlRefTablePtr) doc->refs;
2949 if (table == NULL)
2950 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002951
Daniel Veillard37721922001-05-04 15:21:12 +00002952 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00002953}
2954
2955/************************************************************************
2956 * *
2957 * Routines for validity checking *
2958 * *
2959 ************************************************************************/
2960
2961/**
2962 * xmlGetDtdElementDesc:
2963 * @dtd: a pointer to the DtD to search
2964 * @name: the element name
2965 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002966 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002967 *
2968 * returns the xmlElementPtr if found or NULL
2969 */
2970
2971xmlElementPtr
2972xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2973 xmlElementTablePtr table;
2974 xmlElementPtr cur;
2975 xmlChar *uqname = NULL, *prefix = NULL;
2976
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002977 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002978 if (dtd->elements == NULL)
2979 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002980 table = (xmlElementTablePtr) dtd->elements;
2981
2982 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002983 if (uqname != NULL)
2984 name = uqname;
2985 cur = xmlHashLookup2(table, name, prefix);
2986 if (prefix != NULL) xmlFree(prefix);
2987 if (uqname != NULL) xmlFree(uqname);
2988 return(cur);
2989}
2990/**
2991 * xmlGetDtdElementDesc2:
2992 * @dtd: a pointer to the DtD to search
2993 * @name: the element name
2994 * @create: create an empty description if not found
2995 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002996 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00002997 *
2998 * returns the xmlElementPtr if found or NULL
2999 */
3000
Daniel Veillard86fd5a72001-12-13 14:55:21 +00003001static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00003002xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3003 xmlElementTablePtr table;
3004 xmlElementPtr cur;
3005 xmlChar *uqname = NULL, *prefix = NULL;
3006
3007 if (dtd == NULL) return(NULL);
3008 if (dtd->elements == NULL) {
3009 if (!create)
3010 return(NULL);
3011 /*
3012 * Create the Element table if needed.
3013 */
3014 table = (xmlElementTablePtr) dtd->elements;
3015 if (table == NULL) {
3016 table = xmlCreateElementTable();
3017 dtd->elements = (void *) table;
3018 }
3019 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003020 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003021 return(NULL);
3022 }
3023 }
3024 table = (xmlElementTablePtr) dtd->elements;
3025
3026 uqname = xmlSplitQName2(name, &prefix);
3027 if (uqname != NULL)
3028 name = uqname;
3029 cur = xmlHashLookup2(table, name, prefix);
3030 if ((cur == NULL) && (create)) {
3031 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3032 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003033 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003034 return(NULL);
3035 }
3036 memset(cur, 0, sizeof(xmlElement));
3037 cur->type = XML_ELEMENT_DECL;
3038
3039 /*
3040 * fill the structure.
3041 */
3042 cur->name = xmlStrdup(name);
3043 cur->prefix = xmlStrdup(prefix);
3044 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3045
3046 xmlHashAddEntry2(table, name, prefix, cur);
3047 }
3048 if (prefix != NULL) xmlFree(prefix);
3049 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003050 return(cur);
3051}
3052
3053/**
3054 * xmlGetDtdQElementDesc:
3055 * @dtd: a pointer to the DtD to search
3056 * @name: the element name
3057 * @prefix: the element namespace prefix
3058 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003059 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003060 *
3061 * returns the xmlElementPtr if found or NULL
3062 */
3063
Daniel Veillard48da9102001-08-07 01:10:10 +00003064xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003065xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3066 const xmlChar *prefix) {
3067 xmlElementTablePtr table;
3068
3069 if (dtd == NULL) return(NULL);
3070 if (dtd->elements == NULL) return(NULL);
3071 table = (xmlElementTablePtr) dtd->elements;
3072
3073 return(xmlHashLookup2(table, name, prefix));
3074}
3075
3076/**
3077 * xmlGetDtdAttrDesc:
3078 * @dtd: a pointer to the DtD to search
3079 * @elem: the element name
3080 * @name: the attribute name
3081 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003082 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003083 * this element.
3084 *
3085 * returns the xmlAttributePtr if found or NULL
3086 */
3087
3088xmlAttributePtr
3089xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3090 xmlAttributeTablePtr table;
3091 xmlAttributePtr cur;
3092 xmlChar *uqname = NULL, *prefix = NULL;
3093
3094 if (dtd == NULL) return(NULL);
3095 if (dtd->attributes == NULL) return(NULL);
3096
3097 table = (xmlAttributeTablePtr) dtd->attributes;
3098 if (table == NULL)
3099 return(NULL);
3100
3101 uqname = xmlSplitQName2(name, &prefix);
3102
3103 if (uqname != NULL) {
3104 cur = xmlHashLookup3(table, uqname, prefix, elem);
3105 if (prefix != NULL) xmlFree(prefix);
3106 if (uqname != NULL) xmlFree(uqname);
3107 } else
3108 cur = xmlHashLookup3(table, name, NULL, elem);
3109 return(cur);
3110}
3111
3112/**
3113 * xmlGetDtdQAttrDesc:
3114 * @dtd: a pointer to the DtD to search
3115 * @elem: the element name
3116 * @name: the attribute name
3117 * @prefix: the attribute namespace prefix
3118 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003119 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003120 * this element.
3121 *
3122 * returns the xmlAttributePtr if found or NULL
3123 */
3124
Daniel Veillard48da9102001-08-07 01:10:10 +00003125xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003126xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3127 const xmlChar *prefix) {
3128 xmlAttributeTablePtr table;
3129
3130 if (dtd == NULL) return(NULL);
3131 if (dtd->attributes == NULL) return(NULL);
3132 table = (xmlAttributeTablePtr) dtd->attributes;
3133
3134 return(xmlHashLookup3(table, name, prefix, elem));
3135}
3136
3137/**
3138 * xmlGetDtdNotationDesc:
3139 * @dtd: a pointer to the DtD to search
3140 * @name: the notation name
3141 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003142 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003143 *
3144 * returns the xmlNotationPtr if found or NULL
3145 */
3146
3147xmlNotationPtr
3148xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3149 xmlNotationTablePtr table;
3150
3151 if (dtd == NULL) return(NULL);
3152 if (dtd->notations == NULL) return(NULL);
3153 table = (xmlNotationTablePtr) dtd->notations;
3154
3155 return(xmlHashLookup(table, name));
3156}
3157
Daniel Veillardf54cd532004-02-25 11:52:31 +00003158#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003159/**
3160 * xmlValidateNotationUse:
3161 * @ctxt: the validation context
3162 * @doc: the document
3163 * @notationName: the notation name to check
3164 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003165 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003166 * - [ VC: Notation Declared ]
3167 *
3168 * returns 1 if valid or 0 otherwise
3169 */
3170
3171int
3172xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3173 const xmlChar *notationName) {
3174 xmlNotationPtr notaDecl;
3175 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3176
3177 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3178 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3179 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3180
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003181 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003182 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3183 "NOTATION %s is not declared\n",
3184 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003185 return(0);
3186 }
3187 return(1);
3188}
Daniel Veillardf54cd532004-02-25 11:52:31 +00003189#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003190
3191/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003192 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003193 * @doc: the document
3194 * @name: the element name
3195 *
3196 * Search in the DtDs whether an element accept Mixed content (or ANY)
3197 * basically if it is supposed to accept text childs
3198 *
3199 * returns 0 if no, 1 if yes, and -1 if no element description is available
3200 */
3201
3202int
3203xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3204 xmlElementPtr elemDecl;
3205
3206 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3207
3208 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3209 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3210 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3211 if (elemDecl == NULL) return(-1);
3212 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003213 case XML_ELEMENT_TYPE_UNDEFINED:
3214 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003215 case XML_ELEMENT_TYPE_ELEMENT:
3216 return(0);
3217 case XML_ELEMENT_TYPE_EMPTY:
3218 /*
3219 * return 1 for EMPTY since we want VC error to pop up
3220 * on <empty> </empty> for example
3221 */
3222 case XML_ELEMENT_TYPE_ANY:
3223 case XML_ELEMENT_TYPE_MIXED:
3224 return(1);
3225 }
3226 return(1);
3227}
3228
Daniel Veillard4432df22003-09-28 18:58:27 +00003229#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003230/**
3231 * xmlValidateNameValue:
3232 * @value: an Name value
3233 *
3234 * Validate that the given value match Name production
3235 *
3236 * returns 1 if valid or 0 otherwise
3237 */
3238
Daniel Veillard9b731d72002-04-14 12:56:08 +00003239int
Owen Taylor3473f882001-02-23 17:55:21 +00003240xmlValidateNameValue(const xmlChar *value) {
3241 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003242 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003243
3244 if (value == NULL) return(0);
3245 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003246 val = xmlStringCurrentChar(NULL, cur, &len);
3247 cur += len;
3248 if (!IS_LETTER(val) && (val != '_') &&
3249 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003250 return(0);
3251 }
3252
Daniel Veillardd8224e02002-01-13 15:43:22 +00003253 val = xmlStringCurrentChar(NULL, cur, &len);
3254 cur += len;
3255 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3256 (val == '.') || (val == '-') ||
3257 (val == '_') || (val == ':') ||
3258 (IS_COMBINING(val)) ||
3259 (IS_EXTENDER(val))) {
3260 val = xmlStringCurrentChar(NULL, cur, &len);
3261 cur += len;
3262 }
Owen Taylor3473f882001-02-23 17:55:21 +00003263
Daniel Veillardd8224e02002-01-13 15:43:22 +00003264 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003265
3266 return(1);
3267}
3268
3269/**
3270 * xmlValidateNamesValue:
3271 * @value: an Names value
3272 *
3273 * Validate that the given value match Names production
3274 *
3275 * returns 1 if valid or 0 otherwise
3276 */
3277
Daniel Veillard9b731d72002-04-14 12:56:08 +00003278int
Owen Taylor3473f882001-02-23 17:55:21 +00003279xmlValidateNamesValue(const xmlChar *value) {
3280 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003281 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003282
3283 if (value == NULL) return(0);
3284 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003285 val = xmlStringCurrentChar(NULL, cur, &len);
3286 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003287
Daniel Veillardd8224e02002-01-13 15:43:22 +00003288 if (!IS_LETTER(val) && (val != '_') &&
3289 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003290 return(0);
3291 }
3292
Daniel Veillardd8224e02002-01-13 15:43:22 +00003293 val = xmlStringCurrentChar(NULL, cur, &len);
3294 cur += len;
3295 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3296 (val == '.') || (val == '-') ||
3297 (val == '_') || (val == ':') ||
3298 (IS_COMBINING(val)) ||
3299 (IS_EXTENDER(val))) {
3300 val = xmlStringCurrentChar(NULL, cur, &len);
3301 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003302 }
3303
Daniel Veillardd8224e02002-01-13 15:43:22 +00003304 while (IS_BLANK(val)) {
3305 while (IS_BLANK(val)) {
3306 val = xmlStringCurrentChar(NULL, cur, &len);
3307 cur += len;
3308 }
3309
3310 if (!IS_LETTER(val) && (val != '_') &&
3311 (val != ':')) {
3312 return(0);
3313 }
3314 val = xmlStringCurrentChar(NULL, cur, &len);
3315 cur += len;
3316
3317 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3318 (val == '.') || (val == '-') ||
3319 (val == '_') || (val == ':') ||
3320 (IS_COMBINING(val)) ||
3321 (IS_EXTENDER(val))) {
3322 val = xmlStringCurrentChar(NULL, cur, &len);
3323 cur += len;
3324 }
3325 }
3326
3327 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003328
3329 return(1);
3330}
3331
3332/**
3333 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003334 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003335 *
3336 * Validate that the given value match Nmtoken production
3337 *
3338 * [ VC: Name Token ]
3339 *
3340 * returns 1 if valid or 0 otherwise
3341 */
3342
Daniel Veillard9b731d72002-04-14 12:56:08 +00003343int
Owen Taylor3473f882001-02-23 17:55:21 +00003344xmlValidateNmtokenValue(const xmlChar *value) {
3345 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003346 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003347
3348 if (value == NULL) return(0);
3349 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003350 val = xmlStringCurrentChar(NULL, cur, &len);
3351 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003352
Daniel Veillardd8224e02002-01-13 15:43:22 +00003353 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3354 (val != '.') && (val != '-') &&
3355 (val != '_') && (val != ':') &&
3356 (!IS_COMBINING(val)) &&
3357 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003358 return(0);
3359
Daniel Veillardd8224e02002-01-13 15:43:22 +00003360 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3361 (val == '.') || (val == '-') ||
3362 (val == '_') || (val == ':') ||
3363 (IS_COMBINING(val)) ||
3364 (IS_EXTENDER(val))) {
3365 val = xmlStringCurrentChar(NULL, cur, &len);
3366 cur += len;
3367 }
Owen Taylor3473f882001-02-23 17:55:21 +00003368
Daniel Veillardd8224e02002-01-13 15:43:22 +00003369 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003370
3371 return(1);
3372}
3373
3374/**
3375 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003376 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003377 *
3378 * Validate that the given value match Nmtokens production
3379 *
3380 * [ VC: Name Token ]
3381 *
3382 * returns 1 if valid or 0 otherwise
3383 */
3384
Daniel Veillard9b731d72002-04-14 12:56:08 +00003385int
Owen Taylor3473f882001-02-23 17:55:21 +00003386xmlValidateNmtokensValue(const xmlChar *value) {
3387 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003388 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003389
3390 if (value == NULL) return(0);
3391 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003392 val = xmlStringCurrentChar(NULL, cur, &len);
3393 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003394
Daniel Veillardd8224e02002-01-13 15:43:22 +00003395 while (IS_BLANK(val)) {
3396 val = xmlStringCurrentChar(NULL, cur, &len);
3397 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003398 }
3399
Daniel Veillardd8224e02002-01-13 15:43:22 +00003400 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3401 (val != '.') && (val != '-') &&
3402 (val != '_') && (val != ':') &&
3403 (!IS_COMBINING(val)) &&
3404 (!IS_EXTENDER(val)))
3405 return(0);
3406
3407 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3408 (val == '.') || (val == '-') ||
3409 (val == '_') || (val == ':') ||
3410 (IS_COMBINING(val)) ||
3411 (IS_EXTENDER(val))) {
3412 val = xmlStringCurrentChar(NULL, cur, &len);
3413 cur += len;
3414 }
3415
3416 while (IS_BLANK(val)) {
3417 while (IS_BLANK(val)) {
3418 val = xmlStringCurrentChar(NULL, cur, &len);
3419 cur += len;
3420 }
3421 if (val == 0) return(1);
3422
3423 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3424 (val != '.') && (val != '-') &&
3425 (val != '_') && (val != ':') &&
3426 (!IS_COMBINING(val)) &&
3427 (!IS_EXTENDER(val)))
3428 return(0);
3429
3430 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3431 (val == '.') || (val == '-') ||
3432 (val == '_') || (val == ':') ||
3433 (IS_COMBINING(val)) ||
3434 (IS_EXTENDER(val))) {
3435 val = xmlStringCurrentChar(NULL, cur, &len);
3436 cur += len;
3437 }
3438 }
3439
3440 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003441
3442 return(1);
3443}
3444
3445/**
3446 * xmlValidateNotationDecl:
3447 * @ctxt: the validation context
3448 * @doc: a document instance
3449 * @nota: a notation definition
3450 *
3451 * Try to validate a single notation definition
3452 * basically it does the following checks as described by the
3453 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003454 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003455 * But this function get called anyway ...
3456 *
3457 * returns 1 if valid or 0 otherwise
3458 */
3459
3460int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003461xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3462 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003463 int ret = 1;
3464
3465 return(ret);
3466}
3467
3468/**
3469 * xmlValidateAttributeValue:
3470 * @type: an attribute type
3471 * @value: an attribute value
3472 *
3473 * Validate that the given attribute value match the proper production
3474 *
3475 * [ VC: ID ]
3476 * Values of type ID must match the Name production....
3477 *
3478 * [ VC: IDREF ]
3479 * Values of type IDREF must match the Name production, and values
3480 * of type IDREFS must match Names ...
3481 *
3482 * [ VC: Entity Name ]
3483 * Values of type ENTITY must match the Name production, values
3484 * of type ENTITIES must match Names ...
3485 *
3486 * [ VC: Name Token ]
3487 * Values of type NMTOKEN must match the Nmtoken production; values
3488 * of type NMTOKENS must match Nmtokens.
3489 *
3490 * returns 1 if valid or 0 otherwise
3491 */
3492
3493int
3494xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3495 switch (type) {
3496 case XML_ATTRIBUTE_ENTITIES:
3497 case XML_ATTRIBUTE_IDREFS:
3498 return(xmlValidateNamesValue(value));
3499 case XML_ATTRIBUTE_ENTITY:
3500 case XML_ATTRIBUTE_IDREF:
3501 case XML_ATTRIBUTE_ID:
3502 case XML_ATTRIBUTE_NOTATION:
3503 return(xmlValidateNameValue(value));
3504 case XML_ATTRIBUTE_NMTOKENS:
3505 case XML_ATTRIBUTE_ENUMERATION:
3506 return(xmlValidateNmtokensValue(value));
3507 case XML_ATTRIBUTE_NMTOKEN:
3508 return(xmlValidateNmtokenValue(value));
3509 case XML_ATTRIBUTE_CDATA:
3510 break;
3511 }
3512 return(1);
3513}
3514
3515/**
3516 * xmlValidateAttributeValue2:
3517 * @ctxt: the validation context
3518 * @doc: the document
3519 * @name: the attribute name (used for error reporting only)
3520 * @type: the attribute type
3521 * @value: the attribute value
3522 *
3523 * Validate that the given attribute value match a given type.
3524 * This typically cannot be done before having finished parsing
3525 * the subsets.
3526 *
3527 * [ VC: IDREF ]
3528 * Values of type IDREF must match one of the declared IDs
3529 * Values of type IDREFS must match a sequence of the declared IDs
3530 * each Name must match the value of an ID attribute on some element
3531 * in the XML document; i.e. IDREF values must match the value of
3532 * some ID attribute
3533 *
3534 * [ VC: Entity Name ]
3535 * Values of type ENTITY must match one declared entity
3536 * Values of type ENTITIES must match a sequence of declared entities
3537 *
3538 * [ VC: Notation Attributes ]
3539 * all notation names in the declaration must be declared.
3540 *
3541 * returns 1 if valid or 0 otherwise
3542 */
3543
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003544static int
Owen Taylor3473f882001-02-23 17:55:21 +00003545xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3546 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3547 int ret = 1;
3548 switch (type) {
3549 case XML_ATTRIBUTE_IDREFS:
3550 case XML_ATTRIBUTE_IDREF:
3551 case XML_ATTRIBUTE_ID:
3552 case XML_ATTRIBUTE_NMTOKENS:
3553 case XML_ATTRIBUTE_ENUMERATION:
3554 case XML_ATTRIBUTE_NMTOKEN:
3555 case XML_ATTRIBUTE_CDATA:
3556 break;
3557 case XML_ATTRIBUTE_ENTITY: {
3558 xmlEntityPtr ent;
3559
3560 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003561 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003562 if ((ent == NULL) && (doc->standalone == 1)) {
3563 doc->standalone = 0;
3564 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003565 }
Owen Taylor3473f882001-02-23 17:55:21 +00003566 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003567 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3568 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003569 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003570 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003571 ret = 0;
3572 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003573 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3574 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003575 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003576 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003577 ret = 0;
3578 }
3579 break;
3580 }
3581 case XML_ATTRIBUTE_ENTITIES: {
3582 xmlChar *dup, *nam = NULL, *cur, save;
3583 xmlEntityPtr ent;
3584
3585 dup = xmlStrdup(value);
3586 if (dup == NULL)
3587 return(0);
3588 cur = dup;
3589 while (*cur != 0) {
3590 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003591 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003592 save = *cur;
3593 *cur = 0;
3594 ent = xmlGetDocEntity(doc, nam);
3595 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003596 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3597 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003598 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003599 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003600 ret = 0;
3601 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003602 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3603 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003604 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003605 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003606 ret = 0;
3607 }
3608 if (save == 0)
3609 break;
3610 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003611 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003612 }
3613 xmlFree(dup);
3614 break;
3615 }
3616 case XML_ATTRIBUTE_NOTATION: {
3617 xmlNotationPtr nota;
3618
3619 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3620 if ((nota == NULL) && (doc->extSubset != NULL))
3621 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3622
3623 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003624 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3625 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003626 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003627 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003628 ret = 0;
3629 }
3630 break;
3631 }
3632 }
3633 return(ret);
3634}
3635
3636/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003637 * xmlValidCtxtNormalizeAttributeValue:
3638 * @ctxt: the validation context
3639 * @doc: the document
3640 * @elem: the parent
3641 * @name: the attribute name
3642 * @value: the attribute value
3643 * @ctxt: the validation context or NULL
3644 *
3645 * Does the validation related extra step of the normalization of attribute
3646 * values:
3647 *
3648 * If the declared value is not CDATA, then the XML processor must further
3649 * process the normalized attribute value by discarding any leading and
3650 * trailing space (#x20) characters, and by replacing sequences of space
3651 * (#x20) characters by single space (#x20) character.
3652 *
3653 * Also check VC: Standalone Document Declaration in P32, and update
3654 * ctxt->valid accordingly
3655 *
3656 * returns a new normalized string if normalization is needed, NULL otherwise
3657 * the caller must free the returned value.
3658 */
3659
3660xmlChar *
3661xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3662 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3663 xmlChar *ret, *dst;
3664 const xmlChar *src;
3665 xmlAttributePtr attrDecl = NULL;
3666 int extsubset = 0;
3667
3668 if (doc == NULL) return(NULL);
3669 if (elem == NULL) return(NULL);
3670 if (name == NULL) return(NULL);
3671 if (value == NULL) return(NULL);
3672
3673 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003674 xmlChar fn[50];
3675 xmlChar *fullname;
3676
3677 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3678 if (fullname == NULL)
3679 return(0);
3680 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003681 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003682 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003683 if (attrDecl != NULL)
3684 extsubset = 1;
3685 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003686 if ((fullname != fn) && (fullname != elem->name))
3687 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003688 }
3689 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3690 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3691 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3692 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3693 if (attrDecl != NULL)
3694 extsubset = 1;
3695 }
3696
3697 if (attrDecl == NULL)
3698 return(NULL);
3699 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3700 return(NULL);
3701
3702 ret = xmlStrdup(value);
3703 if (ret == NULL)
3704 return(NULL);
3705 src = value;
3706 dst = ret;
3707 while (*src == 0x20) src++;
3708 while (*src != 0) {
3709 if (*src == 0x20) {
3710 while (*src == 0x20) src++;
3711 if (*src != 0)
3712 *dst++ = 0x20;
3713 } else {
3714 *dst++ = *src++;
3715 }
3716 }
3717 *dst = 0;
3718 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003719 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003720"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003721 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003722 ctxt->valid = 0;
3723 }
3724 return(ret);
3725}
3726
3727/**
Owen Taylor3473f882001-02-23 17:55:21 +00003728 * xmlValidNormalizeAttributeValue:
3729 * @doc: the document
3730 * @elem: the parent
3731 * @name: the attribute name
3732 * @value: the attribute value
3733 *
3734 * Does the validation related extra step of the normalization of attribute
3735 * values:
3736 *
3737 * If the declared value is not CDATA, then the XML processor must further
3738 * process the normalized attribute value by discarding any leading and
3739 * trailing space (#x20) characters, and by replacing sequences of space
3740 * (#x20) characters by single space (#x20) character.
3741 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003742 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003743 * the caller must free the returned value.
3744 */
3745
3746xmlChar *
3747xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3748 const xmlChar *name, const xmlChar *value) {
3749 xmlChar *ret, *dst;
3750 const xmlChar *src;
3751 xmlAttributePtr attrDecl = NULL;
3752
3753 if (doc == NULL) return(NULL);
3754 if (elem == NULL) return(NULL);
3755 if (name == NULL) return(NULL);
3756 if (value == NULL) return(NULL);
3757
3758 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003759 xmlChar fn[50];
3760 xmlChar *fullname;
3761
3762 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3763 if (fullname == NULL)
3764 return(0);
3765 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003766 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003767 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3768 if ((fullname != fn) && (fullname != elem->name))
3769 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003770 }
3771 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3772 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3773 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3774
3775 if (attrDecl == NULL)
3776 return(NULL);
3777 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3778 return(NULL);
3779
3780 ret = xmlStrdup(value);
3781 if (ret == NULL)
3782 return(NULL);
3783 src = value;
3784 dst = ret;
3785 while (*src == 0x20) src++;
3786 while (*src != 0) {
3787 if (*src == 0x20) {
3788 while (*src == 0x20) src++;
3789 if (*src != 0)
3790 *dst++ = 0x20;
3791 } else {
3792 *dst++ = *src++;
3793 }
3794 }
3795 *dst = 0;
3796 return(ret);
3797}
3798
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003799static void
Owen Taylor3473f882001-02-23 17:55:21 +00003800xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003801 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003802 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3803}
3804
3805/**
3806 * xmlValidateAttributeDecl:
3807 * @ctxt: the validation context
3808 * @doc: a document instance
3809 * @attr: an attribute definition
3810 *
3811 * Try to validate a single attribute definition
3812 * basically it does the following checks as described by the
3813 * XML-1.0 recommendation:
3814 * - [ VC: Attribute Default Legal ]
3815 * - [ VC: Enumeration ]
3816 * - [ VC: ID Attribute Default ]
3817 *
3818 * The ID/IDREF uniqueness and matching are done separately
3819 *
3820 * returns 1 if valid or 0 otherwise
3821 */
3822
3823int
3824xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3825 xmlAttributePtr attr) {
3826 int ret = 1;
3827 int val;
3828 CHECK_DTD;
3829 if(attr == NULL) return(1);
3830
3831 /* Attribute Default Legal */
3832 /* Enumeration */
3833 if (attr->defaultValue != NULL) {
3834 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3835 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003836 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003837 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003838 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003839 }
3840 ret &= val;
3841 }
3842
3843 /* ID Attribute Default */
3844 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3845 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3846 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003847 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003848 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003849 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003850 ret = 0;
3851 }
3852
3853 /* One ID per Element Type */
3854 if (attr->atype == XML_ATTRIBUTE_ID) {
3855 int nbId;
3856
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003857 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00003858 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3859 attr->elem);
3860 if (elem != NULL) {
3861 nbId = xmlScanIDAttributeDecl(NULL, elem);
3862 } else {
3863 xmlAttributeTablePtr table;
3864
3865 /*
3866 * The attribute may be declared in the internal subset and the
3867 * element in the external subset.
3868 */
3869 nbId = 0;
3870 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3871 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3872 xmlValidateAttributeIdCallback, &nbId);
3873 }
3874 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003875
3876 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003877 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3878 attr->elem, nbId, attr->name);
3879 } else if (doc->extSubset != NULL) {
3880 int extId = 0;
3881 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3882 if (elem != NULL) {
3883 extId = xmlScanIDAttributeDecl(NULL, elem);
3884 }
3885 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003886 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003887 "Element %s has %d ID attribute defined in the external subset : %s\n",
3888 attr->elem, extId, attr->name);
3889 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003890 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003891"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003892 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003893 }
3894 }
3895 }
3896
3897 /* Validity Constraint: Enumeration */
3898 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3899 xmlEnumerationPtr tree = attr->tree;
3900 while (tree != NULL) {
3901 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3902 tree = tree->next;
3903 }
3904 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003905 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003906"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003907 attr->defaultValue, attr->name, attr->elem);
3908 ret = 0;
3909 }
3910 }
3911
3912 return(ret);
3913}
3914
3915/**
3916 * xmlValidateElementDecl:
3917 * @ctxt: the validation context
3918 * @doc: a document instance
3919 * @elem: an element definition
3920 *
3921 * Try to validate a single element definition
3922 * basically it does the following checks as described by the
3923 * XML-1.0 recommendation:
3924 * - [ VC: One ID per Element Type ]
3925 * - [ VC: No Duplicate Types ]
3926 * - [ VC: Unique Element Type Declaration ]
3927 *
3928 * returns 1 if valid or 0 otherwise
3929 */
3930
3931int
3932xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3933 xmlElementPtr elem) {
3934 int ret = 1;
3935 xmlElementPtr tst;
3936
3937 CHECK_DTD;
3938
3939 if (elem == NULL) return(1);
3940
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003941#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00003942#ifdef LIBXML_REGEXP_ENABLED
3943 /* Build the regexp associated to the content model */
3944 ret = xmlValidBuildContentModel(ctxt, elem);
3945#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003946#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00003947
Owen Taylor3473f882001-02-23 17:55:21 +00003948 /* No Duplicate Types */
3949 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3950 xmlElementContentPtr cur, next;
3951 const xmlChar *name;
3952
3953 cur = elem->content;
3954 while (cur != NULL) {
3955 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3956 if (cur->c1 == NULL) break;
3957 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3958 name = cur->c1->name;
3959 next = cur->c2;
3960 while (next != NULL) {
3961 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00003962 if ((xmlStrEqual(next->name, name)) &&
3963 (xmlStrEqual(next->prefix, cur->prefix))) {
3964 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003965 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00003966 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003967 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003968 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003969 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003970 "Definition of %s has duplicate references of %s:%s\n",
3971 elem->name, cur->prefix, name);
3972 }
Owen Taylor3473f882001-02-23 17:55:21 +00003973 ret = 0;
3974 }
3975 break;
3976 }
3977 if (next->c1 == NULL) break;
3978 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00003979 if ((xmlStrEqual(next->c1->name, name)) &&
3980 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
3981 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003982 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003983 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003984 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003985 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003986 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003987 "Definition of %s has duplicate references to %s:%s\n",
3988 elem->name, cur->prefix, name);
3989 }
Owen Taylor3473f882001-02-23 17:55:21 +00003990 ret = 0;
3991 }
3992 next = next->c2;
3993 }
3994 }
3995 cur = cur->c2;
3996 }
3997 }
3998
3999 /* VC: Unique Element Type Declaration */
4000 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004001 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004002 ((tst->prefix == elem->prefix) ||
4003 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004004 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004005 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4006 "Redefinition of element %s\n",
4007 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004008 ret = 0;
4009 }
4010 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004011 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004012 ((tst->prefix == elem->prefix) ||
4013 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004014 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004015 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4016 "Redefinition of element %s\n",
4017 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004018 ret = 0;
4019 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004020 /* One ID per Element Type
4021 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004022 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4023 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004024 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004025 return(ret);
4026}
4027
4028/**
4029 * xmlValidateOneAttribute:
4030 * @ctxt: the validation context
4031 * @doc: a document instance
4032 * @elem: an element instance
4033 * @attr: an attribute instance
4034 * @value: the attribute value (without entities processing)
4035 *
4036 * Try to validate a single attribute for an element
4037 * basically it does the following checks as described by the
4038 * XML-1.0 recommendation:
4039 * - [ VC: Attribute Value Type ]
4040 * - [ VC: Fixed Attribute Default ]
4041 * - [ VC: Entity Name ]
4042 * - [ VC: Name Token ]
4043 * - [ VC: ID ]
4044 * - [ VC: IDREF ]
4045 * - [ VC: Entity Name ]
4046 * - [ VC: Notation Attributes ]
4047 *
4048 * The ID/IDREF uniqueness and matching are done separately
4049 *
4050 * returns 1 if valid or 0 otherwise
4051 */
4052
4053int
4054xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004055 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4056{
Owen Taylor3473f882001-02-23 17:55:21 +00004057 xmlAttributePtr attrDecl = NULL;
4058 int val;
4059 int ret = 1;
4060
4061 CHECK_DTD;
4062 if ((elem == NULL) || (elem->name == NULL)) return(0);
4063 if ((attr == NULL) || (attr->name == NULL)) return(0);
4064
4065 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004066 xmlChar fn[50];
4067 xmlChar *fullname;
4068
4069 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4070 if (fullname == NULL)
4071 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004072 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004073 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004074 attr->name, attr->ns->prefix);
4075 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004076 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004077 attr->name, attr->ns->prefix);
4078 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004079 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004080 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4081 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004082 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004083 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004084 if ((fullname != fn) && (fullname != elem->name))
4085 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004086 }
4087 if (attrDecl == NULL) {
4088 if (attr->ns != NULL) {
4089 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4090 attr->name, attr->ns->prefix);
4091 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4092 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4093 attr->name, attr->ns->prefix);
4094 } else {
4095 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4096 elem->name, attr->name);
4097 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4098 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4099 elem->name, attr->name);
4100 }
4101 }
4102
4103
4104 /* Validity Constraint: Attribute Value Type */
4105 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004106 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004107 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004108 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004109 return(0);
4110 }
4111 attr->atype = attrDecl->atype;
4112
4113 val = xmlValidateAttributeValue(attrDecl->atype, value);
4114 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004115 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004116 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004117 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004118 ret = 0;
4119 }
4120
4121 /* Validity constraint: Fixed Attribute Default */
4122 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4123 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004124 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004125 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004126 attr->name, elem->name, attrDecl->defaultValue);
4127 ret = 0;
4128 }
4129 }
4130
4131 /* Validity Constraint: ID uniqueness */
4132 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4133 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4134 ret = 0;
4135 }
4136
4137 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4138 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4139 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4140 ret = 0;
4141 }
4142
4143 /* Validity Constraint: Notation Attributes */
4144 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4145 xmlEnumerationPtr tree = attrDecl->tree;
4146 xmlNotationPtr nota;
4147
4148 /* First check that the given NOTATION was declared */
4149 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4150 if (nota == NULL)
4151 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4152
4153 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004154 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004155 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004156 value, attr->name, elem->name);
4157 ret = 0;
4158 }
4159
4160 /* Second, verify that it's among the list */
4161 while (tree != NULL) {
4162 if (xmlStrEqual(tree->name, value)) break;
4163 tree = tree->next;
4164 }
4165 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004166 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004167"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004168 value, attr->name, elem->name);
4169 ret = 0;
4170 }
4171 }
4172
4173 /* Validity Constraint: Enumeration */
4174 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4175 xmlEnumerationPtr tree = attrDecl->tree;
4176 while (tree != NULL) {
4177 if (xmlStrEqual(tree->name, value)) break;
4178 tree = tree->next;
4179 }
4180 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004181 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004182 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004183 value, attr->name, elem->name);
4184 ret = 0;
4185 }
4186 }
4187
4188 /* Fixed Attribute Default */
4189 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4190 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004191 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004192 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004193 attr->name, elem->name, attrDecl->defaultValue);
4194 ret = 0;
4195 }
4196
4197 /* Extra check for the attribute value */
4198 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4199 attrDecl->atype, value);
4200
4201 return(ret);
4202}
4203
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004204/**
4205 * xmlValidateOneNamespace:
4206 * @ctxt: the validation context
4207 * @doc: a document instance
4208 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004209 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004210 * @ns: an namespace declaration instance
4211 * @value: the attribute value (without entities processing)
4212 *
4213 * Try to validate a single namespace declaration for an element
4214 * basically it does the following checks as described by the
4215 * XML-1.0 recommendation:
4216 * - [ VC: Attribute Value Type ]
4217 * - [ VC: Fixed Attribute Default ]
4218 * - [ VC: Entity Name ]
4219 * - [ VC: Name Token ]
4220 * - [ VC: ID ]
4221 * - [ VC: IDREF ]
4222 * - [ VC: Entity Name ]
4223 * - [ VC: Notation Attributes ]
4224 *
4225 * The ID/IDREF uniqueness and matching are done separately
4226 *
4227 * returns 1 if valid or 0 otherwise
4228 */
4229
4230int
4231xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4232xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4233 /* xmlElementPtr elemDecl; */
4234 xmlAttributePtr attrDecl = NULL;
4235 int val;
4236 int ret = 1;
4237
4238 CHECK_DTD;
4239 if ((elem == NULL) || (elem->name == NULL)) return(0);
4240 if ((ns == NULL) || (ns->href == NULL)) return(0);
4241
4242 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004243 xmlChar fn[50];
4244 xmlChar *fullname;
4245
4246 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4247 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004248 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004249 return(0);
4250 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004251 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004252 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004253 ns->prefix, BAD_CAST "xmlns");
4254 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004255 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004256 ns->prefix, BAD_CAST "xmlns");
4257 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004258 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004259 BAD_CAST "xmlns");
4260 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004261 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004262 BAD_CAST "xmlns");
4263 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004264 if ((fullname != fn) && (fullname != elem->name))
4265 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004266 }
4267 if (attrDecl == NULL) {
4268 if (ns->prefix != NULL) {
4269 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4270 ns->prefix, BAD_CAST "xmlns");
4271 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4272 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4273 ns->prefix, BAD_CAST "xmlns");
4274 } else {
4275 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4276 elem->name, BAD_CAST "xmlns");
4277 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4278 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4279 elem->name, BAD_CAST "xmlns");
4280 }
4281 }
4282
4283
4284 /* Validity Constraint: Attribute Value Type */
4285 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004286 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004287 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004288 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004289 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004290 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004291 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004292 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004293 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004294 }
4295 return(0);
4296 }
4297
4298 val = xmlValidateAttributeValue(attrDecl->atype, value);
4299 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004300 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004301 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004302 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004303 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004304 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004305 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004306 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004307 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004308 }
4309 ret = 0;
4310 }
4311
4312 /* Validity constraint: Fixed Attribute Default */
4313 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4314 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004315 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004316 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004317 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4318 ns->prefix, elem->name, attrDecl->defaultValue);
4319 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004320 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004321 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004322 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004323 }
4324 ret = 0;
4325 }
4326 }
4327
4328 /* Validity Constraint: ID uniqueness */
4329 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4330 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4331 ret = 0;
4332 }
4333
4334 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4335 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4336 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4337 ret = 0;
4338 }
4339
4340 /* Validity Constraint: Notation Attributes */
4341 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4342 xmlEnumerationPtr tree = attrDecl->tree;
4343 xmlNotationPtr nota;
4344
4345 /* First check that the given NOTATION was declared */
4346 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4347 if (nota == NULL)
4348 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4349
4350 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004351 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004352 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004353 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4354 value, ns->prefix, elem->name);
4355 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004356 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004357 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004358 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004359 }
4360 ret = 0;
4361 }
4362
4363 /* Second, verify that it's among the list */
4364 while (tree != NULL) {
4365 if (xmlStrEqual(tree->name, value)) break;
4366 tree = tree->next;
4367 }
4368 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004369 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004370 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004371"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4372 value, ns->prefix, elem->name);
4373 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004374 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004375"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004376 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004377 }
4378 ret = 0;
4379 }
4380 }
4381
4382 /* Validity Constraint: Enumeration */
4383 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4384 xmlEnumerationPtr tree = attrDecl->tree;
4385 while (tree != NULL) {
4386 if (xmlStrEqual(tree->name, value)) break;
4387 tree = tree->next;
4388 }
4389 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004390 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004391 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004392"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4393 value, ns->prefix, elem->name);
4394 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004395 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004396"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004397 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004398 }
4399 ret = 0;
4400 }
4401 }
4402
4403 /* Fixed Attribute Default */
4404 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4405 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004406 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004407 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004408 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4409 ns->prefix, elem->name, attrDecl->defaultValue);
4410 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004411 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004412 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004413 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004414 }
4415 ret = 0;
4416 }
4417
4418 /* Extra check for the attribute value */
4419 if (ns->prefix != NULL) {
4420 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4421 attrDecl->atype, value);
4422 } else {
4423 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4424 attrDecl->atype, value);
4425 }
4426
4427 return(ret);
4428}
4429
Daniel Veillard118aed72002-09-24 14:13:13 +00004430#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004431/**
4432 * xmlValidateSkipIgnorable:
4433 * @ctxt: the validation context
4434 * @child: the child list
4435 *
4436 * Skip ignorable elements w.r.t. the validation process
4437 *
4438 * returns the first element to consider for validation of the content model
4439 */
4440
4441static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004442xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004443 while (child != NULL) {
4444 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004445 /* These things are ignored (skipped) during validation. */
4446 case XML_PI_NODE:
4447 case XML_COMMENT_NODE:
4448 case XML_XINCLUDE_START:
4449 case XML_XINCLUDE_END:
4450 child = child->next;
4451 break;
4452 case XML_TEXT_NODE:
4453 if (xmlIsBlankNode(child))
4454 child = child->next;
4455 else
4456 return(child);
4457 break;
4458 /* keep current node */
4459 default:
4460 return(child);
4461 }
4462 }
4463 return(child);
4464}
4465
4466/**
4467 * xmlValidateElementType:
4468 * @ctxt: the validation context
4469 *
4470 * Try to validate the content model of an element internal function
4471 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004472 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4473 * reference is found and -3 if the validation succeeded but
4474 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004475 */
4476
4477static int
4478xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004479 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004480 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004481
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004482 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004483 if ((NODE == NULL) && (CONT == NULL))
4484 return(1);
4485 if ((NODE == NULL) &&
4486 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4487 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4488 return(1);
4489 }
4490 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004491 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004492 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004493
4494 /*
4495 * We arrive here when more states need to be examined
4496 */
4497cont:
4498
4499 /*
4500 * We just recovered from a rollback generated by a possible
4501 * epsilon transition, go directly to the analysis phase
4502 */
4503 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004504 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004505 DEBUG_VALID_STATE(NODE, CONT)
4506 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004507 goto analyze;
4508 }
4509
4510 DEBUG_VALID_STATE(NODE, CONT)
4511 /*
4512 * we may have to save a backup state here. This is the equivalent
4513 * of handling epsilon transition in NFAs.
4514 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004515 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004516 ((CONT->parent == NULL) ||
4517 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004518 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004519 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004520 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004521 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004522 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4523 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004524 }
4525
4526
4527 /*
4528 * Check first if the content matches
4529 */
4530 switch (CONT->type) {
4531 case XML_ELEMENT_CONTENT_PCDATA:
4532 if (NODE == NULL) {
4533 DEBUG_VALID_MSG("pcdata failed no node");
4534 ret = 0;
4535 break;
4536 }
4537 if (NODE->type == XML_TEXT_NODE) {
4538 DEBUG_VALID_MSG("pcdata found, skip to next");
4539 /*
4540 * go to next element in the content model
4541 * skipping ignorable elems
4542 */
4543 do {
4544 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004545 NODE = xmlValidateSkipIgnorable(NODE);
4546 if ((NODE != NULL) &&
4547 (NODE->type == XML_ENTITY_REF_NODE))
4548 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004549 } while ((NODE != NULL) &&
4550 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004551 (NODE->type != XML_TEXT_NODE) &&
4552 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004553 ret = 1;
4554 break;
4555 } else {
4556 DEBUG_VALID_MSG("pcdata failed");
4557 ret = 0;
4558 break;
4559 }
4560 break;
4561 case XML_ELEMENT_CONTENT_ELEMENT:
4562 if (NODE == NULL) {
4563 DEBUG_VALID_MSG("element failed no node");
4564 ret = 0;
4565 break;
4566 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004567 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4568 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004569 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004570 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4571 ret = (CONT->prefix == NULL);
4572 } else if (CONT->prefix == NULL) {
4573 ret = 0;
4574 } else {
4575 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4576 }
4577 }
4578 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004579 DEBUG_VALID_MSG("element found, skip to next");
4580 /*
4581 * go to next element in the content model
4582 * skipping ignorable elems
4583 */
4584 do {
4585 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004586 NODE = xmlValidateSkipIgnorable(NODE);
4587 if ((NODE != NULL) &&
4588 (NODE->type == XML_ENTITY_REF_NODE))
4589 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004590 } while ((NODE != NULL) &&
4591 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004592 (NODE->type != XML_TEXT_NODE) &&
4593 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004594 } else {
4595 DEBUG_VALID_MSG("element failed");
4596 ret = 0;
4597 break;
4598 }
4599 break;
4600 case XML_ELEMENT_CONTENT_OR:
4601 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004602 * Small optimization.
4603 */
4604 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4605 if ((NODE == NULL) ||
4606 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4607 DEPTH++;
4608 CONT = CONT->c2;
4609 goto cont;
4610 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004611 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4612 ret = (CONT->c1->prefix == NULL);
4613 } else if (CONT->c1->prefix == NULL) {
4614 ret = 0;
4615 } else {
4616 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4617 }
4618 if (ret == 0) {
4619 DEPTH++;
4620 CONT = CONT->c2;
4621 goto cont;
4622 }
Daniel Veillard85349052001-04-20 13:48:21 +00004623 }
4624
4625 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004626 * save the second branch 'or' branch
4627 */
4628 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004629 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4630 OCCURS, ROLLBACK_OR) < 0)
4631 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004632 DEPTH++;
4633 CONT = CONT->c1;
4634 goto cont;
4635 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004636 /*
4637 * Small optimization.
4638 */
4639 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4640 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4641 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4642 if ((NODE == NULL) ||
4643 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4644 DEPTH++;
4645 CONT = CONT->c2;
4646 goto cont;
4647 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004648 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4649 ret = (CONT->c1->prefix == NULL);
4650 } else if (CONT->c1->prefix == NULL) {
4651 ret = 0;
4652 } else {
4653 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4654 }
4655 if (ret == 0) {
4656 DEPTH++;
4657 CONT = CONT->c2;
4658 goto cont;
4659 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004660 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004661 DEPTH++;
4662 CONT = CONT->c1;
4663 goto cont;
4664 }
4665
4666 /*
4667 * At this point handle going up in the tree
4668 */
4669 if (ret == -1) {
4670 DEBUG_VALID_MSG("error found returning");
4671 return(ret);
4672 }
4673analyze:
4674 while (CONT != NULL) {
4675 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004676 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004677 * this level.
4678 */
4679 if (ret == 0) {
4680 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004681 xmlNodePtr cur;
4682
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004683 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004684 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004685 DEBUG_VALID_MSG("Once branch failed, rollback");
4686 if (vstateVPop(ctxt) < 0 ) {
4687 DEBUG_VALID_MSG("exhaustion, failed");
4688 return(0);
4689 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004690 if (cur != ctxt->vstate->node)
4691 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004692 goto cont;
4693 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004694 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004695 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004696 DEBUG_VALID_MSG("Plus branch failed, rollback");
4697 if (vstateVPop(ctxt) < 0 ) {
4698 DEBUG_VALID_MSG("exhaustion, failed");
4699 return(0);
4700 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004701 if (cur != ctxt->vstate->node)
4702 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004703 goto cont;
4704 }
4705 DEBUG_VALID_MSG("Plus branch found");
4706 ret = 1;
4707 break;
4708 case XML_ELEMENT_CONTENT_MULT:
4709#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004710 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004711 DEBUG_VALID_MSG("Mult branch failed");
4712 } else {
4713 DEBUG_VALID_MSG("Mult branch found");
4714 }
4715#endif
4716 ret = 1;
4717 break;
4718 case XML_ELEMENT_CONTENT_OPT:
4719 DEBUG_VALID_MSG("Option branch failed");
4720 ret = 1;
4721 break;
4722 }
4723 } else {
4724 switch (CONT->ocur) {
4725 case XML_ELEMENT_CONTENT_OPT:
4726 DEBUG_VALID_MSG("Option branch succeeded");
4727 ret = 1;
4728 break;
4729 case XML_ELEMENT_CONTENT_ONCE:
4730 DEBUG_VALID_MSG("Once branch succeeded");
4731 ret = 1;
4732 break;
4733 case XML_ELEMENT_CONTENT_PLUS:
4734 if (STATE == ROLLBACK_PARENT) {
4735 DEBUG_VALID_MSG("Plus branch rollback");
4736 ret = 1;
4737 break;
4738 }
4739 if (NODE == NULL) {
4740 DEBUG_VALID_MSG("Plus branch exhausted");
4741 ret = 1;
4742 break;
4743 }
4744 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004745 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004746 goto cont;
4747 case XML_ELEMENT_CONTENT_MULT:
4748 if (STATE == ROLLBACK_PARENT) {
4749 DEBUG_VALID_MSG("Mult branch rollback");
4750 ret = 1;
4751 break;
4752 }
4753 if (NODE == NULL) {
4754 DEBUG_VALID_MSG("Mult branch exhausted");
4755 ret = 1;
4756 break;
4757 }
4758 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004759 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004760 goto cont;
4761 }
4762 }
4763 STATE = 0;
4764
4765 /*
4766 * Then act accordingly at the parent level
4767 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004768 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004769 if (CONT->parent == NULL)
4770 break;
4771
4772 switch (CONT->parent->type) {
4773 case XML_ELEMENT_CONTENT_PCDATA:
4774 DEBUG_VALID_MSG("Error: parent pcdata");
4775 return(-1);
4776 case XML_ELEMENT_CONTENT_ELEMENT:
4777 DEBUG_VALID_MSG("Error: parent element");
4778 return(-1);
4779 case XML_ELEMENT_CONTENT_OR:
4780 if (ret == 1) {
4781 DEBUG_VALID_MSG("Or succeeded");
4782 CONT = CONT->parent;
4783 DEPTH--;
4784 } else {
4785 DEBUG_VALID_MSG("Or failed");
4786 CONT = CONT->parent;
4787 DEPTH--;
4788 }
4789 break;
4790 case XML_ELEMENT_CONTENT_SEQ:
4791 if (ret == 0) {
4792 DEBUG_VALID_MSG("Sequence failed");
4793 CONT = CONT->parent;
4794 DEPTH--;
4795 } else if (CONT == CONT->parent->c1) {
4796 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4797 CONT = CONT->parent->c2;
4798 goto cont;
4799 } else {
4800 DEBUG_VALID_MSG("Sequence succeeded");
4801 CONT = CONT->parent;
4802 DEPTH--;
4803 }
4804 }
4805 }
4806 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004807 xmlNodePtr cur;
4808
4809 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004810 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4811 if (vstateVPop(ctxt) < 0 ) {
4812 DEBUG_VALID_MSG("exhaustion, failed");
4813 return(0);
4814 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004815 if (cur != ctxt->vstate->node)
4816 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004817 goto cont;
4818 }
4819 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004820 xmlNodePtr cur;
4821
4822 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004823 DEBUG_VALID_MSG("Failure, rollback");
4824 if (vstateVPop(ctxt) < 0 ) {
4825 DEBUG_VALID_MSG("exhaustion, failed");
4826 return(0);
4827 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004828 if (cur != ctxt->vstate->node)
4829 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004830 goto cont;
4831 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004832 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004833}
Daniel Veillard23e73572002-09-19 19:56:43 +00004834#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004835
4836/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00004837 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004838 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00004839 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004840 * @content: An element
4841 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4842 *
4843 * This will dump the list of elements to the buffer
4844 * Intended just for the debug routine
4845 */
4846static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00004847xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004848 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00004849 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004850
4851 if (node == NULL) return;
4852 if (glob) strcat(buf, "(");
4853 cur = node;
4854 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004855 len = strlen(buf);
4856 if (size - len < 50) {
4857 if ((size - len > 4) && (buf[len - 1] != '.'))
4858 strcat(buf, " ...");
4859 return;
4860 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004861 switch (cur->type) {
4862 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004863 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004864 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004865 if ((size - len > 4) && (buf[len - 1] != '.'))
4866 strcat(buf, " ...");
4867 return;
4868 }
4869 strcat(buf, (char *) cur->ns->prefix);
4870 strcat(buf, ":");
4871 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004872 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004873 if ((size - len > 4) && (buf[len - 1] != '.'))
4874 strcat(buf, " ...");
4875 return;
4876 }
4877 strcat(buf, (char *) cur->name);
4878 if (cur->next != NULL)
4879 strcat(buf, " ");
4880 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004881 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004882 if (xmlIsBlankNode(cur))
4883 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004884 case XML_CDATA_SECTION_NODE:
4885 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004886 strcat(buf, "CDATA");
4887 if (cur->next != NULL)
4888 strcat(buf, " ");
4889 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004890 case XML_ATTRIBUTE_NODE:
4891 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004892#ifdef LIBXML_DOCB_ENABLED
4893 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004894#endif
4895 case XML_HTML_DOCUMENT_NODE:
4896 case XML_DOCUMENT_TYPE_NODE:
4897 case XML_DOCUMENT_FRAG_NODE:
4898 case XML_NOTATION_NODE:
4899 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004900 strcat(buf, "???");
4901 if (cur->next != NULL)
4902 strcat(buf, " ");
4903 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004904 case XML_ENTITY_NODE:
4905 case XML_PI_NODE:
4906 case XML_DTD_NODE:
4907 case XML_COMMENT_NODE:
4908 case XML_ELEMENT_DECL:
4909 case XML_ATTRIBUTE_DECL:
4910 case XML_ENTITY_DECL:
4911 case XML_XINCLUDE_START:
4912 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004913 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004914 }
4915 cur = cur->next;
4916 }
4917 if (glob) strcat(buf, ")");
4918}
4919
4920/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004921 * xmlValidateElementContent:
4922 * @ctxt: the validation context
4923 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004924 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004925 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004926 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004927 *
4928 * Try to validate the content model of an element
4929 *
4930 * returns 1 if valid or 0 if not and -1 in case of error
4931 */
4932
4933static int
4934xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004935 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004936 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00004937#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00004938 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00004939#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00004940 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004941 xmlElementContentPtr cont;
4942 const xmlChar *name;
4943
4944 if (elemDecl == NULL)
4945 return(-1);
4946 cont = elemDecl->content;
4947 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004948
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004949#ifdef LIBXML_REGEXP_ENABLED
4950 /* Build the regexp associated to the content model */
4951 if (elemDecl->contModel == NULL)
4952 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4953 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004954 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004955 } else {
4956 xmlRegExecCtxtPtr exec;
4957
Daniel Veillardec498e12003-02-05 11:01:50 +00004958 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
4959 return(-1);
4960 }
Daniel Veillard01992e02002-10-09 10:20:30 +00004961 ctxt->nodeMax = 0;
4962 ctxt->nodeNr = 0;
4963 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004964 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4965 if (exec != NULL) {
4966 cur = child;
4967 while (cur != NULL) {
4968 switch (cur->type) {
4969 case XML_ENTITY_REF_NODE:
4970 /*
4971 * Push the current node to be able to roll back
4972 * and process within the entity
4973 */
4974 if ((cur->children != NULL) &&
4975 (cur->children->children != NULL)) {
4976 nodeVPush(ctxt, cur);
4977 cur = cur->children->children;
4978 continue;
4979 }
4980 break;
4981 case XML_TEXT_NODE:
4982 if (xmlIsBlankNode(cur))
4983 break;
4984 ret = 0;
4985 goto fail;
4986 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00004987 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004988 ret = 0;
4989 goto fail;
4990 case XML_ELEMENT_NODE:
4991 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004992 xmlChar fn[50];
4993 xmlChar *fullname;
4994
4995 fullname = xmlBuildQName(cur->name,
4996 cur->ns->prefix, fn, 50);
4997 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004998 ret = -1;
4999 goto fail;
5000 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005001 ret = xmlRegExecPushString(exec, fullname, NULL);
5002 if ((fullname != fn) && (fullname != cur->name))
5003 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005004 } else {
5005 ret = xmlRegExecPushString(exec, cur->name, NULL);
5006 }
5007 break;
5008 default:
5009 break;
5010 }
5011 /*
5012 * Switch to next element
5013 */
5014 cur = cur->next;
5015 while (cur == NULL) {
5016 cur = nodeVPop(ctxt);
5017 if (cur == NULL)
5018 break;
5019 cur = cur->next;
5020 }
5021 }
5022 ret = xmlRegExecPushString(exec, NULL, NULL);
5023fail:
5024 xmlRegFreeExecCtxt(exec);
5025 }
5026 }
5027#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005028 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005029 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005030 */
5031 ctxt->vstateMax = 8;
5032 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5033 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5034 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005035 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005036 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005037 }
5038 /*
5039 * The first entry in the stack is reserved to the current state
5040 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005041 ctxt->nodeMax = 0;
5042 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005043 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005044 ctxt->vstate = &ctxt->vstateTab[0];
5045 ctxt->vstateNr = 1;
5046 CONT = cont;
5047 NODE = child;
5048 DEPTH = 0;
5049 OCCURS = 0;
5050 STATE = 0;
5051 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005052 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005053 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5054 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005055 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005056 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005057 /*
5058 * An entities reference appeared at this level.
5059 * Buid a minimal representation of this node content
5060 * sufficient to run the validation process on it
5061 */
5062 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005063 cur = child;
5064 while (cur != NULL) {
5065 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005066 case XML_ENTITY_REF_NODE:
5067 /*
5068 * Push the current node to be able to roll back
5069 * and process within the entity
5070 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005071 if ((cur->children != NULL) &&
5072 (cur->children->children != NULL)) {
5073 nodeVPush(ctxt, cur);
5074 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005075 continue;
5076 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005077 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005078 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005079 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005080 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005081 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005082 case XML_CDATA_SECTION_NODE:
5083 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005084 case XML_ELEMENT_NODE:
5085 /*
5086 * Allocate a new node and minimally fills in
5087 * what's required
5088 */
5089 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5090 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005091 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005092 xmlFreeNodeList(repl);
5093 ret = -1;
5094 goto done;
5095 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005096 tmp->type = cur->type;
5097 tmp->name = cur->name;
5098 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005099 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005100 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005101 if (repl == NULL)
5102 repl = last = tmp;
5103 else {
5104 last->next = tmp;
5105 last = tmp;
5106 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005107 if (cur->type == XML_CDATA_SECTION_NODE) {
5108 /*
5109 * E59 spaces in CDATA does not match the
5110 * nonterminal S
5111 */
5112 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5113 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005114 break;
5115 default:
5116 break;
5117 }
5118 /*
5119 * Switch to next element
5120 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005121 cur = cur->next;
5122 while (cur == NULL) {
5123 cur = nodeVPop(ctxt);
5124 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005125 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005126 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005127 }
5128 }
5129
5130 /*
5131 * Relaunch the validation
5132 */
5133 ctxt->vstate = &ctxt->vstateTab[0];
5134 ctxt->vstateNr = 1;
5135 CONT = cont;
5136 NODE = repl;
5137 DEPTH = 0;
5138 OCCURS = 0;
5139 STATE = 0;
5140 ret = xmlValidateElementType(ctxt);
5141 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005142#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005143 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005144 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5145 char expr[5000];
5146 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005147
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005148 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005149 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005150 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005151#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005152 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005153 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005154 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005155#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005156 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005157
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005158 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005159 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5160 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5161 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005162 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005163 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5164 "Element content does not follow the DTD, expecting %s, got %s\n",
5165 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005166 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005167 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005168 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005169 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005170 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005171 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005172 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005173 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5174 "Element content does not follow the DTD\n",
5175 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005176 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005177 }
5178 ret = 0;
5179 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005180 if (ret == -3)
5181 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005182
Daniel Veillard23e73572002-09-19 19:56:43 +00005183#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005184done:
5185 /*
5186 * Deallocate the copy if done, and free up the validation stack
5187 */
5188 while (repl != NULL) {
5189 tmp = repl->next;
5190 xmlFree(repl);
5191 repl = tmp;
5192 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005193 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005194 if (ctxt->vstateTab != NULL) {
5195 xmlFree(ctxt->vstateTab);
5196 ctxt->vstateTab = NULL;
5197 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005198#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005199 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005200 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005201 if (ctxt->nodeTab != NULL) {
5202 xmlFree(ctxt->nodeTab);
5203 ctxt->nodeTab = NULL;
5204 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005205 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005206
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005207}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005208
Owen Taylor3473f882001-02-23 17:55:21 +00005209/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005210 * xmlValidateCdataElement:
5211 * @ctxt: the validation context
5212 * @doc: a document instance
5213 * @elem: an element instance
5214 *
5215 * Check that an element follows #CDATA
5216 *
5217 * returns 1 if valid or 0 otherwise
5218 */
5219static int
5220xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5221 xmlNodePtr elem) {
5222 int ret = 1;
5223 xmlNodePtr cur, child;
5224
Daniel Veillardceb09b92002-10-04 11:46:37 +00005225 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005226 return(0);
5227
5228 child = elem->children;
5229
5230 cur = child;
5231 while (cur != NULL) {
5232 switch (cur->type) {
5233 case XML_ENTITY_REF_NODE:
5234 /*
5235 * Push the current node to be able to roll back
5236 * and process within the entity
5237 */
5238 if ((cur->children != NULL) &&
5239 (cur->children->children != NULL)) {
5240 nodeVPush(ctxt, cur);
5241 cur = cur->children->children;
5242 continue;
5243 }
5244 break;
5245 case XML_COMMENT_NODE:
5246 case XML_PI_NODE:
5247 case XML_TEXT_NODE:
5248 case XML_CDATA_SECTION_NODE:
5249 break;
5250 default:
5251 ret = 0;
5252 goto done;
5253 }
5254 /*
5255 * Switch to next element
5256 */
5257 cur = cur->next;
5258 while (cur == NULL) {
5259 cur = nodeVPop(ctxt);
5260 if (cur == NULL)
5261 break;
5262 cur = cur->next;
5263 }
5264 }
5265done:
5266 ctxt->nodeMax = 0;
5267 ctxt->nodeNr = 0;
5268 if (ctxt->nodeTab != NULL) {
5269 xmlFree(ctxt->nodeTab);
5270 ctxt->nodeTab = NULL;
5271 }
5272 return(ret);
5273}
5274
5275/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005276 * xmlValidateCheckMixed:
5277 * @ctxt: the validation context
5278 * @cont: the mixed content model
5279 * @qname: the qualified name as appearing in the serialization
5280 *
5281 * Check if the given node is part of the content model.
5282 *
5283 * Returns 1 if yes, 0 if no, -1 in case of error
5284 */
5285static int
William M. Brackedb65a72004-02-06 07:36:04 +00005286xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005287 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005288 const xmlChar *name;
5289 int plen;
5290 name = xmlSplitQName3(qname, &plen);
5291
5292 if (name == NULL) {
5293 while (cont != NULL) {
5294 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5295 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5296 return(1);
5297 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5298 (cont->c1 != NULL) &&
5299 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5300 if ((cont->c1->prefix == NULL) &&
5301 (xmlStrEqual(cont->c1->name, qname)))
5302 return(1);
5303 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5304 (cont->c1 == NULL) ||
5305 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005306 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5307 "Internal: MIXED struct corrupted\n",
5308 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005309 break;
5310 }
5311 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005312 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005313 } else {
5314 while (cont != NULL) {
5315 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5316 if ((cont->prefix != NULL) &&
5317 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5318 (xmlStrEqual(cont->name, name)))
5319 return(1);
5320 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5321 (cont->c1 != NULL) &&
5322 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5323 if ((cont->c1->prefix != NULL) &&
5324 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5325 (xmlStrEqual(cont->c1->name, name)))
5326 return(1);
5327 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5328 (cont->c1 == NULL) ||
5329 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005330 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5331 "Internal: MIXED struct corrupted\n",
5332 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005333 break;
5334 }
5335 cont = cont->c2;
5336 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005337 }
5338 return(0);
5339}
5340
5341/**
5342 * xmlValidGetElemDecl:
5343 * @ctxt: the validation context
5344 * @doc: a document instance
5345 * @elem: an element instance
5346 * @extsubset: pointer, (out) indicate if the declaration was found
5347 * in the external subset.
5348 *
5349 * Finds a declaration associated to an element in the document.
5350 *
5351 * returns the pointer to the declaration or NULL if not found.
5352 */
5353static xmlElementPtr
5354xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5355 xmlNodePtr elem, int *extsubset) {
5356 xmlElementPtr elemDecl = NULL;
5357 const xmlChar *prefix = NULL;
5358
5359 if ((elem == NULL) || (elem->name == NULL)) return(NULL);
5360 if (extsubset != NULL)
5361 *extsubset = 0;
5362
5363 /*
5364 * Fetch the declaration for the qualified name
5365 */
5366 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5367 prefix = elem->ns->prefix;
5368
5369 if (prefix != NULL) {
5370 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5371 elem->name, prefix);
5372 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5373 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5374 elem->name, prefix);
5375 if ((elemDecl != NULL) && (extsubset != NULL))
5376 *extsubset = 1;
5377 }
5378 }
5379
5380 /*
5381 * Fetch the declaration for the non qualified name
5382 * This is "non-strict" validation should be done on the
5383 * full QName but in that case being flexible makes sense.
5384 */
5385 if (elemDecl == NULL) {
5386 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5387 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5388 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5389 if ((elemDecl != NULL) && (extsubset != NULL))
5390 *extsubset = 1;
5391 }
5392 }
5393 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005394 xmlErrValidNode(ctxt, elem,
5395 XML_DTD_UNKNOWN_ELEM,
5396 "No declaration for element %s\n",
5397 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005398 }
5399 return(elemDecl);
5400}
5401
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005402#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005403/**
5404 * xmlValidatePushElement:
5405 * @ctxt: the validation context
5406 * @doc: a document instance
5407 * @elem: an element instance
5408 * @qname: the qualified name as appearing in the serialization
5409 *
5410 * Push a new element start on the validation stack.
5411 *
5412 * returns 1 if no validation problem was found or 0 otherwise
5413 */
5414int
5415xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5416 xmlNodePtr elem, const xmlChar *qname) {
5417 int ret = 1;
5418 xmlElementPtr eDecl;
5419 int extsubset = 0;
5420
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005421/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005422 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5423 xmlValidStatePtr state = ctxt->vstate;
5424 xmlElementPtr elemDecl;
5425
5426 /*
5427 * Check the new element agaisnt the content model of the new elem.
5428 */
5429 if (state->elemDecl != NULL) {
5430 elemDecl = state->elemDecl;
5431
5432 switch(elemDecl->etype) {
5433 case XML_ELEMENT_TYPE_UNDEFINED:
5434 ret = 0;
5435 break;
5436 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005437 xmlErrValidNode(ctxt, state->node,
5438 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005439 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005440 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005441 ret = 0;
5442 break;
5443 case XML_ELEMENT_TYPE_ANY:
5444 /* I don't think anything is required then */
5445 break;
5446 case XML_ELEMENT_TYPE_MIXED:
5447 /* simple case of declared as #PCDATA */
5448 if ((elemDecl->content != NULL) &&
5449 (elemDecl->content->type ==
5450 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005451 xmlErrValidNode(ctxt, state->node,
5452 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005453 "Element %s was declared #PCDATA but contains non text nodes\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 } else {
5457 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5458 qname);
5459 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005460 xmlErrValidNode(ctxt, state->node,
5461 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005462 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005463 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005464 }
5465 }
5466 break;
5467 case XML_ELEMENT_TYPE_ELEMENT:
5468 /*
5469 * TODO:
5470 * VC: Standalone Document Declaration
5471 * - element types with element content, if white space
5472 * occurs directly within any instance of those types.
5473 */
5474 if (state->exec != NULL) {
5475 ret = xmlRegExecPushString(state->exec, qname, NULL);
5476 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005477 xmlErrValidNode(ctxt, state->node,
5478 XML_DTD_CONTENT_MODEL,
5479 "Element %s content does not follow the DTD, Misplaced %s\n",
5480 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005481 ret = 0;
5482 } else {
5483 ret = 1;
5484 }
5485 }
5486 break;
5487 }
5488 }
5489 }
5490 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5491 vstateVPush(ctxt, eDecl, elem);
5492 return(ret);
5493}
5494
5495/**
5496 * xmlValidatePushCData:
5497 * @ctxt: the validation context
5498 * @data: some character data read
5499 * @len: the lenght of the data
5500 *
5501 * check the CData parsed for validation in the current stack
5502 *
5503 * returns 1 if no validation problem was found or 0 otherwise
5504 */
5505int
5506xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5507 int ret = 1;
5508
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005509/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005510 if (len <= 0)
5511 return(ret);
5512 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5513 xmlValidStatePtr state = ctxt->vstate;
5514 xmlElementPtr elemDecl;
5515
5516 /*
5517 * Check the new element agaisnt the content model of the new elem.
5518 */
5519 if (state->elemDecl != NULL) {
5520 elemDecl = state->elemDecl;
5521
5522 switch(elemDecl->etype) {
5523 case XML_ELEMENT_TYPE_UNDEFINED:
5524 ret = 0;
5525 break;
5526 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005527 xmlErrValidNode(ctxt, state->node,
5528 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005529 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005530 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005531 ret = 0;
5532 break;
5533 case XML_ELEMENT_TYPE_ANY:
5534 break;
5535 case XML_ELEMENT_TYPE_MIXED:
5536 break;
5537 case XML_ELEMENT_TYPE_ELEMENT:
5538 if (len > 0) {
5539 int i;
5540
5541 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005542 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005543 xmlErrValidNode(ctxt, state->node,
5544 XML_DTD_CONTENT_MODEL,
5545 "Element %s content does not follow the DTD, Text not allowed\n",
5546 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005547 ret = 0;
5548 goto done;
5549 }
5550 }
5551 /*
5552 * TODO:
5553 * VC: Standalone Document Declaration
5554 * element types with element content, if white space
5555 * occurs directly within any instance of those types.
5556 */
5557 }
5558 break;
5559 }
5560 }
5561 }
5562done:
5563 return(ret);
5564}
5565
5566/**
5567 * xmlValidatePopElement:
5568 * @ctxt: the validation context
5569 * @doc: a document instance
5570 * @elem: an element instance
5571 * @qname: the qualified name as appearing in the serialization
5572 *
5573 * Pop the element end from the validation stack.
5574 *
5575 * returns 1 if no validation problem was found or 0 otherwise
5576 */
5577int
5578xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005579 xmlNodePtr elem ATTRIBUTE_UNUSED,
5580 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005581 int ret = 1;
5582
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005583/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005584 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5585 xmlValidStatePtr state = ctxt->vstate;
5586 xmlElementPtr elemDecl;
5587
5588 /*
5589 * Check the new element agaisnt the content model of the new elem.
5590 */
5591 if (state->elemDecl != NULL) {
5592 elemDecl = state->elemDecl;
5593
5594 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5595 if (state->exec != NULL) {
5596 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5597 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005598 xmlErrValidNode(ctxt, state->node,
5599 XML_DTD_CONTENT_MODEL,
5600 "Element %s content does not follow the DTD, Expecting more child\n",
5601 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005602 } else {
5603 /*
5604 * previous validation errors should not generate
5605 * a new one here
5606 */
5607 ret = 1;
5608 }
5609 }
5610 }
5611 }
5612 vstateVPop(ctxt);
5613 }
5614 return(ret);
5615}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005616#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005617
5618/**
Owen Taylor3473f882001-02-23 17:55:21 +00005619 * xmlValidateOneElement:
5620 * @ctxt: the validation context
5621 * @doc: a document instance
5622 * @elem: an element instance
5623 *
5624 * Try to validate a single element and it's attributes,
5625 * basically it does the following checks as described by the
5626 * XML-1.0 recommendation:
5627 * - [ VC: Element Valid ]
5628 * - [ VC: Required Attribute ]
5629 * Then call xmlValidateOneAttribute() for each attribute present.
5630 *
5631 * The ID/IDREF checkings are done separately
5632 *
5633 * returns 1 if valid or 0 otherwise
5634 */
5635
5636int
5637xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5638 xmlNodePtr elem) {
5639 xmlElementPtr elemDecl = NULL;
5640 xmlElementContentPtr cont;
5641 xmlAttributePtr attr;
5642 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005643 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005644 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005645 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005646
5647 CHECK_DTD;
5648
5649 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005650 switch (elem->type) {
5651 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005652 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5653 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005654 return(0);
5655 case XML_TEXT_NODE:
5656 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005657 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5658 "Text element has children !\n",
5659 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005660 return(0);
5661 }
5662 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005663 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5664 "Text element has attribute !\n",
5665 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005666 return(0);
5667 }
5668 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005669 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5670 "Text element has namespace !\n",
5671 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005672 return(0);
5673 }
5674 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005675 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5676 "Text element has namespace !\n",
5677 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005678 return(0);
5679 }
5680 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005681 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5682 "Text element has no content !\n",
5683 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005684 return(0);
5685 }
5686 return(1);
5687 case XML_XINCLUDE_START:
5688 case XML_XINCLUDE_END:
5689 return(1);
5690 case XML_CDATA_SECTION_NODE:
5691 case XML_ENTITY_REF_NODE:
5692 case XML_PI_NODE:
5693 case XML_COMMENT_NODE:
5694 return(1);
5695 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005696 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5697 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005698 return(0);
5699 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005700 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5701 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005702 return(0);
5703 case XML_DOCUMENT_NODE:
5704 case XML_DOCUMENT_TYPE_NODE:
5705 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005706 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5707 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005708 return(0);
5709 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005710 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5711 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005712 return(0);
5713 case XML_ELEMENT_NODE:
5714 break;
5715 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005716 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5717 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005718 return(0);
5719 }
Owen Taylor3473f882001-02-23 17:55:21 +00005720
5721 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005722 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005723 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005724 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5725 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005726 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005727
Daniel Veillardea7751d2002-12-20 00:16:24 +00005728 /*
5729 * If vstateNr is not zero that means continuous validation is
5730 * activated, do not try to check the content model at that level.
5731 */
5732 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005733 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005734 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005735 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005736 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5737 "No declaration for element %s\n",
5738 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005739 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005740 case XML_ELEMENT_TYPE_EMPTY:
5741 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005742 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005743 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005744 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005745 ret = 0;
5746 }
5747 break;
5748 case XML_ELEMENT_TYPE_ANY:
5749 /* I don't think anything is required then */
5750 break;
5751 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005752
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005753 /* simple case of declared as #PCDATA */
5754 if ((elemDecl->content != NULL) &&
5755 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5756 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5757 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005758 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005759 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005760 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005761 }
5762 break;
5763 }
Owen Taylor3473f882001-02-23 17:55:21 +00005764 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005765 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005766 while (child != NULL) {
5767 if (child->type == XML_ELEMENT_NODE) {
5768 name = child->name;
5769 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005770 xmlChar fn[50];
5771 xmlChar *fullname;
5772
5773 fullname = xmlBuildQName(child->name, child->ns->prefix,
5774 fn, 50);
5775 if (fullname == NULL)
5776 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005777 cont = elemDecl->content;
5778 while (cont != NULL) {
5779 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005780 if (xmlStrEqual(cont->name, fullname))
5781 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005782 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5783 (cont->c1 != NULL) &&
5784 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005785 if (xmlStrEqual(cont->c1->name, fullname))
5786 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005787 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5788 (cont->c1 == NULL) ||
5789 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005790 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5791 "Internal: MIXED struct corrupted\n",
5792 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005793 break;
5794 }
5795 cont = cont->c2;
5796 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005797 if ((fullname != fn) && (fullname != child->name))
5798 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005799 if (cont != NULL)
5800 goto child_ok;
5801 }
5802 cont = elemDecl->content;
5803 while (cont != NULL) {
5804 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5805 if (xmlStrEqual(cont->name, name)) break;
5806 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5807 (cont->c1 != NULL) &&
5808 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5809 if (xmlStrEqual(cont->c1->name, name)) break;
5810 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5811 (cont->c1 == NULL) ||
5812 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005813 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5814 "Internal: MIXED struct corrupted\n",
5815 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005816 break;
5817 }
5818 cont = cont->c2;
5819 }
5820 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005821 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00005822 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005823 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005824 ret = 0;
5825 }
5826 }
5827child_ok:
5828 child = child->next;
5829 }
5830 break;
5831 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005832 if ((doc->standalone == 1) && (extsubset == 1)) {
5833 /*
5834 * VC: Standalone Document Declaration
5835 * - element types with element content, if white space
5836 * occurs directly within any instance of those types.
5837 */
5838 child = elem->children;
5839 while (child != NULL) {
5840 if (child->type == XML_TEXT_NODE) {
5841 const xmlChar *content = child->content;
5842
William M. Brack76e95df2003-10-18 16:20:14 +00005843 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005844 content++;
5845 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005846 xmlErrValidNode(ctxt, elem,
5847 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005848"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005849 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005850 ret = 0;
5851 break;
5852 }
5853 }
5854 child =child->next;
5855 }
5856 }
Owen Taylor3473f882001-02-23 17:55:21 +00005857 child = elem->children;
5858 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005859 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005860 if (tmp <= 0)
5861 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005862 break;
5863 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005864 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00005865
5866 /* [ VC: Required Attribute ] */
5867 attr = elemDecl->attributes;
5868 while (attr != NULL) {
5869 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005870 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005871
Daniel Veillarde4301c82002-02-13 13:32:35 +00005872 if ((attr->prefix == NULL) &&
5873 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5874 xmlNsPtr ns;
5875
5876 ns = elem->nsDef;
5877 while (ns != NULL) {
5878 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005879 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005880 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00005881 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005882 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5883 xmlNsPtr ns;
5884
5885 ns = elem->nsDef;
5886 while (ns != NULL) {
5887 if (xmlStrEqual(attr->name, ns->prefix))
5888 goto found;
5889 ns = ns->next;
5890 }
5891 } else {
5892 xmlAttrPtr attrib;
5893
5894 attrib = elem->properties;
5895 while (attrib != NULL) {
5896 if (xmlStrEqual(attrib->name, attr->name)) {
5897 if (attr->prefix != NULL) {
5898 xmlNsPtr nameSpace = attrib->ns;
5899
5900 if (nameSpace == NULL)
5901 nameSpace = elem->ns;
5902 /*
5903 * qualified names handling is problematic, having a
5904 * different prefix should be possible but DTDs don't
5905 * allow to define the URI instead of the prefix :-(
5906 */
5907 if (nameSpace == NULL) {
5908 if (qualified < 0)
5909 qualified = 0;
5910 } else if (!xmlStrEqual(nameSpace->prefix,
5911 attr->prefix)) {
5912 if (qualified < 1)
5913 qualified = 1;
5914 } else
5915 goto found;
5916 } else {
5917 /*
5918 * We should allow applications to define namespaces
5919 * for their application even if the DTD doesn't
5920 * carry one, otherwise, basically we would always
5921 * break.
5922 */
5923 goto found;
5924 }
5925 }
5926 attrib = attrib->next;
5927 }
Owen Taylor3473f882001-02-23 17:55:21 +00005928 }
5929 if (qualified == -1) {
5930 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005931 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005932 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005933 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005934 ret = 0;
5935 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005936 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005937 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005938 elem->name, attr->prefix,attr->name);
5939 ret = 0;
5940 }
5941 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005942 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005943 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005944 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005945 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005946 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005947 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005948 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005949 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005950 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5951 /*
5952 * Special tests checking #FIXED namespace declarations
5953 * have the right value since this is not done as an
5954 * attribute checking
5955 */
5956 if ((attr->prefix == NULL) &&
5957 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5958 xmlNsPtr ns;
5959
5960 ns = elem->nsDef;
5961 while (ns != NULL) {
5962 if (ns->prefix == NULL) {
5963 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005964 xmlErrValidNode(ctxt, elem,
5965 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00005966 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005967 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005968 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005969 }
5970 goto found;
5971 }
5972 ns = ns->next;
5973 }
5974 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5975 xmlNsPtr ns;
5976
5977 ns = elem->nsDef;
5978 while (ns != NULL) {
5979 if (xmlStrEqual(attr->name, ns->prefix)) {
5980 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005981 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005982 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005983 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005984 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005985 }
5986 goto found;
5987 }
5988 ns = ns->next;
5989 }
5990 }
Owen Taylor3473f882001-02-23 17:55:21 +00005991 }
5992found:
5993 attr = attr->nexth;
5994 }
5995 return(ret);
5996}
5997
5998/**
5999 * xmlValidateRoot:
6000 * @ctxt: the validation context
6001 * @doc: a document instance
6002 *
6003 * Try to validate a the root element
6004 * basically it does the following check as described by the
6005 * XML-1.0 recommendation:
6006 * - [ VC: Root Element Type ]
6007 * it doesn't try to recurse or apply other check to the element
6008 *
6009 * returns 1 if valid or 0 otherwise
6010 */
6011
6012int
6013xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6014 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006015 int ret;
6016
Owen Taylor3473f882001-02-23 17:55:21 +00006017 if (doc == NULL) return(0);
6018
6019 root = xmlDocGetRootElement(doc);
6020 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006021 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6022 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006023 return(0);
6024 }
6025
6026 /*
6027 * When doing post validation against a separate DTD, those may
6028 * no internal subset has been generated
6029 */
6030 if ((doc->intSubset != NULL) &&
6031 (doc->intSubset->name != NULL)) {
6032 /*
6033 * Check first the document root against the NQName
6034 */
6035 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6036 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006037 xmlChar fn[50];
6038 xmlChar *fullname;
6039
6040 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6041 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006042 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006043 return(0);
6044 }
6045 ret = xmlStrEqual(doc->intSubset->name, fullname);
6046 if ((fullname != fn) && (fullname != root->name))
6047 xmlFree(fullname);
6048 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006049 goto name_ok;
6050 }
6051 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6052 (xmlStrEqual(root->name, BAD_CAST "html")))
6053 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006054 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6055 "root and DTD name do not match '%s' and '%s'\n",
6056 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006057 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006058 }
6059 }
6060name_ok:
6061 return(1);
6062}
6063
6064
6065/**
6066 * xmlValidateElement:
6067 * @ctxt: the validation context
6068 * @doc: a document instance
6069 * @elem: an element instance
6070 *
6071 * Try to validate the subtree under an element
6072 *
6073 * returns 1 if valid or 0 otherwise
6074 */
6075
6076int
6077xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6078 xmlNodePtr child;
6079 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006080 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006081 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006082 int ret = 1;
6083
6084 if (elem == NULL) return(0);
6085
6086 /*
6087 * XInclude elements were added after parsing in the infoset,
6088 * they don't really mean anything validation wise.
6089 */
6090 if ((elem->type == XML_XINCLUDE_START) ||
6091 (elem->type == XML_XINCLUDE_END))
6092 return(1);
6093
6094 CHECK_DTD;
6095
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006096 /*
6097 * Entities references have to be handled separately
6098 */
6099 if (elem->type == XML_ENTITY_REF_NODE) {
6100 return(1);
6101 }
6102
Owen Taylor3473f882001-02-23 17:55:21 +00006103 ret &= xmlValidateOneElement(ctxt, doc, elem);
6104 attr = elem->properties;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006105 while (attr != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006106 value = xmlNodeListGetString(doc, attr->children, 0);
6107 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6108 if (value != NULL)
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006109 xmlFree((char *)value);
Owen Taylor3473f882001-02-23 17:55:21 +00006110 attr= attr->next;
6111 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006112 ns = elem->nsDef;
6113 while (ns != NULL) {
Daniel Veillard1f5c9892003-12-29 17:09:55 +00006114 if (elem->ns == NULL)
6115 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6116 ns, ns->href);
6117 else
6118 ret &= xmlValidateOneNamespace(ctxt, doc, elem, elem->ns->prefix,
6119 ns, ns->href);
Daniel Veillarde133dd82003-10-30 10:42:20 +00006120 ns = ns->next;
6121 }
Owen Taylor3473f882001-02-23 17:55:21 +00006122 child = elem->children;
6123 while (child != NULL) {
6124 ret &= xmlValidateElement(ctxt, doc, child);
6125 child = child->next;
6126 }
6127
6128 return(ret);
6129}
6130
Daniel Veillard8730c562001-02-26 10:49:57 +00006131/**
6132 * xmlValidateRef:
6133 * @ref: A reference to be validated
6134 * @ctxt: Validation context
6135 * @name: Name of ID we are searching for
6136 *
6137 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006138static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006139xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006140 const xmlChar *name) {
6141 xmlAttrPtr id;
6142 xmlAttrPtr attr;
6143
6144 if (ref == NULL)
6145 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006146 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006147 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006148 attr = ref->attr;
6149 if (attr == NULL) {
6150 xmlChar *dup, *str = NULL, *cur, save;
6151
6152 dup = xmlStrdup(name);
6153 if (dup == NULL) {
6154 ctxt->valid = 0;
6155 return;
6156 }
6157 cur = dup;
6158 while (*cur != 0) {
6159 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006160 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006161 save = *cur;
6162 *cur = 0;
6163 id = xmlGetID(ctxt->doc, str);
6164 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006165 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006166 "attribute %s line %d references an unknown ID \"%s\"\n",
6167 ref->name, ref->lineno, str);
6168 ctxt->valid = 0;
6169 }
6170 if (save == 0)
6171 break;
6172 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006173 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006174 }
6175 xmlFree(dup);
6176 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006177 id = xmlGetID(ctxt->doc, name);
6178 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006179 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006180 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006181 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006182 ctxt->valid = 0;
6183 }
6184 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6185 xmlChar *dup, *str = NULL, *cur, save;
6186
6187 dup = xmlStrdup(name);
6188 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006189 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006190 ctxt->valid = 0;
6191 return;
6192 }
6193 cur = dup;
6194 while (*cur != 0) {
6195 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006196 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006197 save = *cur;
6198 *cur = 0;
6199 id = xmlGetID(ctxt->doc, str);
6200 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006201 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006202 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006203 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006204 ctxt->valid = 0;
6205 }
6206 if (save == 0)
6207 break;
6208 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006209 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006210 }
6211 xmlFree(dup);
6212 }
6213}
6214
6215/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006216 * xmlWalkValidateList:
6217 * @data: Contents of current link
6218 * @user: Value supplied by the user
6219 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006220 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006221 */
6222static int
6223xmlWalkValidateList(const void *data, const void *user)
6224{
6225 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6226 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6227 return 1;
6228}
6229
6230/**
6231 * xmlValidateCheckRefCallback:
6232 * @ref_list: List of references
6233 * @ctxt: Validation context
6234 * @name: Name of ID we are searching for
6235 *
6236 */
6237static void
6238xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6239 const xmlChar *name) {
6240 xmlValidateMemo memo;
6241
6242 if (ref_list == NULL)
6243 return;
6244 memo.ctxt = ctxt;
6245 memo.name = name;
6246
6247 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6248
6249}
6250
6251/**
Owen Taylor3473f882001-02-23 17:55:21 +00006252 * xmlValidateDocumentFinal:
6253 * @ctxt: the validation context
6254 * @doc: a document instance
6255 *
6256 * Does the final step for the document validation once all the
6257 * incremental validation steps have been completed
6258 *
6259 * basically it does the following checks described by the XML Rec
6260 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006261 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006262 *
6263 * returns 1 if valid or 0 otherwise
6264 */
6265
6266int
6267xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6268 xmlRefTablePtr table;
6269
6270 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006271 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6272 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006273 return(0);
6274 }
6275
6276 /*
6277 * Check all the NOTATION/NOTATIONS attributes
6278 */
6279 /*
6280 * Check all the ENTITY/ENTITIES attributes definition for validity
6281 */
6282 /*
6283 * Check all the IDREF/IDREFS attributes definition for validity
6284 */
6285 table = (xmlRefTablePtr) doc->refs;
6286 ctxt->doc = doc;
6287 ctxt->valid = 1;
6288 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6289 return(ctxt->valid);
6290}
6291
6292/**
6293 * xmlValidateDtd:
6294 * @ctxt: the validation context
6295 * @doc: a document instance
6296 * @dtd: a dtd instance
6297 *
6298 * Try to validate the document against the dtd instance
6299 *
6300 * basically it does check all the definitions in the DtD.
6301 *
6302 * returns 1 if valid or 0 otherwise
6303 */
6304
6305int
6306xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6307 int ret;
6308 xmlDtdPtr oldExt;
6309 xmlNodePtr root;
6310
6311 if (dtd == NULL) return(0);
6312 if (doc == NULL) return(0);
6313 oldExt = doc->extSubset;
6314 doc->extSubset = dtd;
6315 ret = xmlValidateRoot(ctxt, doc);
6316 if (ret == 0) {
6317 doc->extSubset = oldExt;
6318 return(ret);
6319 }
6320 if (doc->ids != NULL) {
6321 xmlFreeIDTable(doc->ids);
6322 doc->ids = NULL;
6323 }
6324 if (doc->refs != NULL) {
6325 xmlFreeRefTable(doc->refs);
6326 doc->refs = NULL;
6327 }
6328 root = xmlDocGetRootElement(doc);
6329 ret = xmlValidateElement(ctxt, doc, root);
6330 ret &= xmlValidateDocumentFinal(ctxt, doc);
6331 doc->extSubset = oldExt;
6332 return(ret);
6333}
6334
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006335static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006336xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6337 const xmlChar *name ATTRIBUTE_UNUSED) {
6338 if (cur == NULL)
6339 return;
6340 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6341 xmlChar *notation = cur->content;
6342
Daniel Veillard878eab02002-02-19 13:46:09 +00006343 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006344 int ret;
6345
6346 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6347 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006348 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006349 }
6350 }
6351 }
6352}
6353
6354static void
Owen Taylor3473f882001-02-23 17:55:21 +00006355xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006356 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006357 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006358 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006359 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006360
Owen Taylor3473f882001-02-23 17:55:21 +00006361 if (cur == NULL)
6362 return;
6363 switch (cur->atype) {
6364 case XML_ATTRIBUTE_CDATA:
6365 case XML_ATTRIBUTE_ID:
6366 case XML_ATTRIBUTE_IDREF :
6367 case XML_ATTRIBUTE_IDREFS:
6368 case XML_ATTRIBUTE_NMTOKEN:
6369 case XML_ATTRIBUTE_NMTOKENS:
6370 case XML_ATTRIBUTE_ENUMERATION:
6371 break;
6372 case XML_ATTRIBUTE_ENTITY:
6373 case XML_ATTRIBUTE_ENTITIES:
6374 case XML_ATTRIBUTE_NOTATION:
6375 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006376
6377 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6378 cur->atype, cur->defaultValue);
6379 if ((ret == 0) && (ctxt->valid == 1))
6380 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006381 }
6382 if (cur->tree != NULL) {
6383 xmlEnumerationPtr tree = cur->tree;
6384 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006385 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006386 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006387 if ((ret == 0) && (ctxt->valid == 1))
6388 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006389 tree = tree->next;
6390 }
6391 }
6392 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006393 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6394 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006395 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006396 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006397 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006398 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006399 return;
6400 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006401
6402 if (doc != NULL)
6403 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6404 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006405 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006406 if ((elem == NULL) && (cur->parent != NULL) &&
6407 (cur->parent->type == XML_DTD_NODE))
6408 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006409 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006410 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006411 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006412 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006413 return;
6414 }
6415 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006416 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006417 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006418 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006419 ctxt->valid = 0;
6420 }
6421 }
Owen Taylor3473f882001-02-23 17:55:21 +00006422}
6423
6424/**
6425 * xmlValidateDtdFinal:
6426 * @ctxt: the validation context
6427 * @doc: a document instance
6428 *
6429 * Does the final step for the dtds validation once all the
6430 * subsets have been parsed
6431 *
6432 * basically it does the following checks described by the XML Rec
6433 * - check that ENTITY and ENTITIES type attributes default or
6434 * possible values matches one of the defined entities.
6435 * - check that NOTATION type attributes default or
6436 * possible values matches one of the defined notations.
6437 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006438 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006439 */
6440
6441int
6442xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006443 xmlDtdPtr dtd;
6444 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006445 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006446
6447 if (doc == NULL) return(0);
6448 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6449 return(0);
6450 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006451 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006452 dtd = doc->intSubset;
6453 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6454 table = (xmlAttributeTablePtr) dtd->attributes;
6455 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006456 }
6457 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006458 entities = (xmlEntitiesTablePtr) dtd->entities;
6459 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6460 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006461 }
6462 dtd = doc->extSubset;
6463 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6464 table = (xmlAttributeTablePtr) dtd->attributes;
6465 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006466 }
6467 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006468 entities = (xmlEntitiesTablePtr) dtd->entities;
6469 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6470 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006471 }
6472 return(ctxt->valid);
6473}
6474
6475/**
6476 * xmlValidateDocument:
6477 * @ctxt: the validation context
6478 * @doc: a document instance
6479 *
6480 * Try to validate the document instance
6481 *
6482 * basically it does the all the checks described by the XML Rec
6483 * i.e. validates the internal and external subset (if present)
6484 * and validate the document tree.
6485 *
6486 * returns 1 if valid or 0 otherwise
6487 */
6488
6489int
6490xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6491 int ret;
6492 xmlNodePtr root;
6493
Daniel Veillard2fd85422002-10-16 14:32:41 +00006494 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006495 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6496 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006497 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006498 }
Owen Taylor3473f882001-02-23 17:55:21 +00006499 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6500 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6501 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6502 doc->intSubset->SystemID);
6503 if (doc->extSubset == NULL) {
6504 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006505 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006506 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006507 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006508 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006509 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006510 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006511 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006512 }
6513 return(0);
6514 }
6515 }
6516
6517 if (doc->ids != NULL) {
6518 xmlFreeIDTable(doc->ids);
6519 doc->ids = NULL;
6520 }
6521 if (doc->refs != NULL) {
6522 xmlFreeRefTable(doc->refs);
6523 doc->refs = NULL;
6524 }
6525 ret = xmlValidateDtdFinal(ctxt, doc);
6526 if (!xmlValidateRoot(ctxt, doc)) return(0);
6527
6528 root = xmlDocGetRootElement(doc);
6529 ret &= xmlValidateElement(ctxt, doc, root);
6530 ret &= xmlValidateDocumentFinal(ctxt, doc);
6531 return(ret);
6532}
6533
Owen Taylor3473f882001-02-23 17:55:21 +00006534/************************************************************************
6535 * *
6536 * Routines for dynamic validation editing *
6537 * *
6538 ************************************************************************/
6539
6540/**
6541 * xmlValidGetPotentialChildren:
6542 * @ctree: an element content tree
6543 * @list: an array to store the list of child names
6544 * @len: a pointer to the number of element in the list
6545 * @max: the size of the array
6546 *
6547 * Build/extend a list of potential children allowed by the content tree
6548 *
6549 * returns the number of element in the list, or -1 in case of error.
6550 */
6551
6552int
6553xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6554 int *len, int max) {
6555 int i;
6556
6557 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6558 return(-1);
6559 if (*len >= max) return(*len);
6560
6561 switch (ctree->type) {
6562 case XML_ELEMENT_CONTENT_PCDATA:
6563 for (i = 0; i < *len;i++)
6564 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6565 list[(*len)++] = BAD_CAST "#PCDATA";
6566 break;
6567 case XML_ELEMENT_CONTENT_ELEMENT:
6568 for (i = 0; i < *len;i++)
6569 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6570 list[(*len)++] = ctree->name;
6571 break;
6572 case XML_ELEMENT_CONTENT_SEQ:
6573 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6574 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6575 break;
6576 case XML_ELEMENT_CONTENT_OR:
6577 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6578 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6579 break;
6580 }
6581
6582 return(*len);
6583}
6584
6585/**
6586 * xmlValidGetValidElements:
6587 * @prev: an element to insert after
6588 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006589 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006590 * @max: the size of the array
6591 *
6592 * This function returns the list of authorized children to insert
6593 * within an existing tree while respecting the validity constraints
6594 * forced by the Dtd. The insertion point is defined using @prev and
6595 * @next in the following ways:
6596 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6597 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6598 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6599 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6600 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6601 *
6602 * pointers to the element names are inserted at the beginning of the array
6603 * and do not need to be freed.
6604 *
6605 * returns the number of element in the list, or -1 in case of error. If
6606 * the function returns the value @max the caller is invited to grow the
6607 * receiving array and retry.
6608 */
6609
6610int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006611xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006612 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006613 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006614 int nb_valid_elements = 0;
6615 const xmlChar *elements[256];
6616 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006617 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006618
6619 xmlNode *ref_node;
6620 xmlNode *parent;
6621 xmlNode *test_node;
6622
6623 xmlNode *prev_next;
6624 xmlNode *next_prev;
6625 xmlNode *parent_childs;
6626 xmlNode *parent_last;
6627
6628 xmlElement *element_desc;
6629
Daniel Veillardbb4e46d2002-03-10 16:49:08 +00006630 memset(&vctxt, 0, sizeof (xmlValidCtxt));
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006631
Owen Taylor3473f882001-02-23 17:55:21 +00006632 if (prev == NULL && next == NULL)
6633 return(-1);
6634
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006635 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006636 if (max <= 0) return(-1);
6637
6638 nb_valid_elements = 0;
6639 ref_node = prev ? prev : next;
6640 parent = ref_node->parent;
6641
6642 /*
6643 * Retrieves the parent element declaration
6644 */
6645 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6646 parent->name);
6647 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6648 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6649 parent->name);
6650 if (element_desc == NULL) return(-1);
6651
6652 /*
6653 * Do a backup of the current tree structure
6654 */
6655 prev_next = prev ? prev->next : NULL;
6656 next_prev = next ? next->prev : NULL;
6657 parent_childs = parent->children;
6658 parent_last = parent->last;
6659
6660 /*
6661 * Creates a dummy node and insert it into the tree
6662 */
6663 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
6664 test_node->doc = ref_node->doc;
6665 test_node->parent = parent;
6666 test_node->prev = prev;
6667 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006668 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006669
6670 if (prev) prev->next = test_node;
6671 else parent->children = test_node;
6672
6673 if (next) next->prev = test_node;
6674 else parent->last = test_node;
6675
6676 /*
6677 * Insert each potential child node and check if the parent is
6678 * still valid
6679 */
6680 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6681 elements, &nb_elements, 256);
6682
6683 for (i = 0;i < nb_elements;i++) {
6684 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006685 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006686 int j;
6687
6688 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006689 if (xmlStrEqual(elements[i], names[j])) break;
6690 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00006691 if (nb_valid_elements >= max) break;
6692 }
6693 }
6694
6695 /*
6696 * Restore the tree structure
6697 */
6698 if (prev) prev->next = prev_next;
6699 if (next) next->prev = next_prev;
6700 parent->children = parent_childs;
6701 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006702
6703 /*
6704 * Free up the dummy node
6705 */
6706 test_node->name = name;
6707 xmlFreeNode(test_node);
6708
Owen Taylor3473f882001-02-23 17:55:21 +00006709 return(nb_valid_elements);
6710}
Daniel Veillard4432df22003-09-28 18:58:27 +00006711#endif /* LIBXML_VALID_ENABLED */
6712