blob: 2510b8d6a49a00a9072c9093e30a7780ebfdc54d [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>
Daniel Veillard29b17482004-08-16 00:39:03 +000021#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <libxml/valid.h>
23#include <libxml/parser.h>
24#include <libxml/parserInternals.h>
25#include <libxml/xmlerror.h>
26#include <libxml/list.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000027#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000028
Daniel Veillard4432df22003-09-28 18:58:27 +000029static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
30 int create);
Daniel Veillarde62d36c2001-05-15 08:53:16 +000031/* #define DEBUG_VALID_ALGO */
Daniel Veillard5acfd6b2002-09-18 16:29:02 +000032/* #define DEBUG_REGEXP_ALGO */
Daniel Veillarde62d36c2001-05-15 08:53:16 +000033
Daniel Veillarda646cfd2002-09-17 21:50:03 +000034#define TODO \
35 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
37 __FILE__, __LINE__);
Owen Taylor3473f882001-02-23 17:55:21 +000038
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000039/************************************************************************
40 * *
41 * Error handling routines *
42 * *
43 ************************************************************************/
44
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000045/**
Daniel Veillardce9457f2003-10-05 21:33:18 +000046 * xmlVErrMemory:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000047 * @ctxt: an XML validation parser context
48 * @extra: extra informations
49 *
50 * Handle an out of memory error
51 */
52static void
Daniel Veillardce9457f2003-10-05 21:33:18 +000053xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000054{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000055 xmlGenericErrorFunc channel = NULL;
56 xmlParserCtxtPtr pctxt = NULL;
57 void *data = NULL;
58
59 if (ctxt != NULL) {
60 channel = ctxt->error;
61 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +000062 /* Use the special values to detect if it is part of a parsing
63 context */
64 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
65 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +000066 long delta = (char *) ctxt - (char *) ctxt->userData;
67 if ((delta > 0) && (delta < 250))
68 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +000069 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +000070 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000071 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000072 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000073 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000074 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
75 "Memory allocation failed : %s\n", extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000076 else
Daniel Veillard73000572003-10-11 11:26:42 +000077 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000078 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000079 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
80 "Memory allocation failed\n");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000081}
82
83/**
84 * xmlErrValid:
85 * @ctxt: an XML validation parser context
Daniel Veillardbb5abab2003-10-03 22:21:51 +000086 * @error: the error number
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000087 * @extra: extra informations
88 *
89 * Handle a validation error
90 */
91static void
Daniel Veillardf88d8cf2003-12-08 10:25:02 +000092xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000093 const char *msg, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000094{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000095 xmlGenericErrorFunc channel = NULL;
96 xmlParserCtxtPtr pctxt = NULL;
97 void *data = NULL;
98
99 if (ctxt != NULL) {
100 channel = ctxt->error;
101 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000102 /* Use the special values to detect if it is part of a parsing
103 context */
104 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
105 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +0000106 long delta = (char *) ctxt - (char *) ctxt->userData;
107 if ((delta > 0) && (delta < 250))
108 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000109 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000110 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000111 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +0000112 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000113 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000114 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
115 msg, extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000116 else
Daniel Veillard73000572003-10-11 11:26:42 +0000117 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000118 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000119 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
120 msg);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000121}
122
Daniel Veillardf54cd532004-02-25 11:52:31 +0000123#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
124/**
125 * xmlErrValidNode:
126 * @ctxt: an XML validation parser context
127 * @node: the node raising the error
128 * @error: the error number
129 * @str1: extra informations
130 * @str2: extra informations
131 * @str3: extra informations
132 *
133 * Handle a validation error, provide contextual informations
134 */
135static void
136xmlErrValidNode(xmlValidCtxtPtr ctxt,
137 xmlNodePtr node, xmlParserErrors error,
138 const char *msg, const xmlChar * str1,
139 const xmlChar * str2, const xmlChar * str3)
140{
141 xmlStructuredErrorFunc schannel = NULL;
142 xmlGenericErrorFunc channel = NULL;
143 xmlParserCtxtPtr pctxt = NULL;
144 void *data = NULL;
145
146 if (ctxt != NULL) {
147 channel = ctxt->error;
148 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000149 /* Use the special values to detect if it is part of a parsing
150 context */
151 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
152 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +0000153 long delta = (char *) ctxt - (char *) ctxt->userData;
154 if ((delta > 0) && (delta < 250))
155 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000156 }
Daniel Veillardf54cd532004-02-25 11:52:31 +0000157 }
158 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
159 XML_ERR_ERROR, NULL, 0,
160 (const char *) str1,
161 (const char *) str1,
162 (const char *) str3, 0, 0, msg, str1, str2, str3);
163}
164#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
165
Daniel Veillardd61e8fb2003-10-19 21:59:17 +0000166#ifdef LIBXML_VALID_ENABLED
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000167/**
168 * xmlErrValidNodeNr:
169 * @ctxt: an XML validation parser context
170 * @node: the node raising the error
171 * @error: the error number
172 * @str1: extra informations
173 * @int2: extra informations
174 * @str3: extra informations
175 *
176 * Handle a validation error, provide contextual informations
177 */
178static void
Daniel Veillard72b9e292003-10-28 15:44:17 +0000179xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000180 xmlNodePtr node, xmlParserErrors error,
181 const char *msg, const xmlChar * str1,
182 int int2, const xmlChar * str3)
183{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000184 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000185 xmlGenericErrorFunc channel = NULL;
186 xmlParserCtxtPtr pctxt = NULL;
187 void *data = NULL;
188
189 if (ctxt != NULL) {
190 channel = ctxt->error;
191 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000192 /* Use the special values to detect if it is part of a parsing
193 context */
194 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
195 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +0000196 long delta = (char *) ctxt - (char *) ctxt->userData;
197 if ((delta > 0) && (delta < 250))
198 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000199 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000200 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000201 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000202 XML_ERR_ERROR, NULL, 0,
203 (const char *) str1,
204 (const char *) str3,
205 NULL, int2, 0, msg, str1, int2, str3);
206}
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000207
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000208/**
209 * xmlErrValidWarning:
210 * @ctxt: an XML validation parser context
211 * @node: the node raising the error
212 * @error: the error number
William M. Brackedb65a72004-02-06 07:36:04 +0000213 * @str1: extra information
214 * @str2: extra information
215 * @str3: extra information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000216 *
William M. Brackedb65a72004-02-06 07:36:04 +0000217 * Handle a validation error, provide contextual information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000218 */
219static void
William M. Brackedb65a72004-02-06 07:36:04 +0000220xmlErrValidWarning(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000221 xmlNodePtr node, xmlParserErrors error,
222 const char *msg, const xmlChar * str1,
223 const xmlChar * str2, const xmlChar * str3)
224{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000225 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000226 xmlGenericErrorFunc channel = NULL;
227 xmlParserCtxtPtr pctxt = NULL;
228 void *data = NULL;
229
230 if (ctxt != NULL) {
William M. Bracke4d526f2004-12-18 00:01:21 +0000231 channel = ctxt->warning;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000232 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000233 /* Use the special values to detect if it is part of a parsing
234 context */
235 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
236 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +0000237 long delta = (char *) ctxt - (char *) ctxt->userData;
238 if ((delta > 0) && (delta < 250))
239 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000240 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000241 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000242 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000243 XML_ERR_WARNING, NULL, 0,
244 (const char *) str1,
245 (const char *) str1,
246 (const char *) str3, 0, 0, msg, str1, str2, str3);
247}
248
249
Daniel Veillardea7751d2002-12-20 00:16:24 +0000250
251#ifdef LIBXML_REGEXP_ENABLED
252/*
253 * If regexp are enabled we can do continuous validation without the
254 * need of a tree to validate the content model. this is done in each
255 * callbacks.
256 * Each xmlValidState represent the validation state associated to the
257 * set of nodes currently open from the document root to the current element.
258 */
259
260
261typedef struct _xmlValidState {
262 xmlElementPtr elemDecl; /* pointer to the content model */
263 xmlNodePtr node; /* pointer to the current node */
264 xmlRegExecCtxtPtr exec; /* regexp runtime */
265} _xmlValidState;
266
267
268static int
269vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000270 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000271 ctxt->vstateMax = 10;
272 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
273 sizeof(ctxt->vstateTab[0]));
274 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000275 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000276 return(-1);
277 }
278 }
279
280 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000281 xmlValidState *tmp;
282
283 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
284 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
285 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000286 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000287 return(-1);
288 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000289 ctxt->vstateMax *= 2;
290 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000291 }
292 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
293 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
294 ctxt->vstateTab[ctxt->vstateNr].node = node;
295 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
296 if (elemDecl->contModel == NULL)
297 xmlValidBuildContentModel(ctxt, elemDecl);
298 if (elemDecl->contModel != NULL) {
299 ctxt->vstateTab[ctxt->vstateNr].exec =
300 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
301 } else {
302 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000303 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
304 XML_ERR_INTERNAL_ERROR,
305 "Failed to build content model regexp for %s\n",
306 node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000307 }
308 }
309 return(ctxt->vstateNr++);
310}
311
312static int
313vstateVPop(xmlValidCtxtPtr ctxt) {
314 xmlElementPtr elemDecl;
315
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000316 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000317 ctxt->vstateNr--;
318 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
319 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
320 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
321 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
322 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
323 }
324 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
325 if (ctxt->vstateNr >= 1)
326 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
327 else
328 ctxt->vstate = NULL;
329 return(ctxt->vstateNr);
330}
331
332#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000333/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000334 * If regexp are not enabled, it uses a home made algorithm less
335 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000336 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000337 * only restriction is on the deepness of the tree limited by the
338 * size of the occurs bitfield
339 *
340 * this is the content of a saved state for rollbacks
341 */
342
343#define ROLLBACK_OR 0
344#define ROLLBACK_PARENT 1
345
Daniel Veillardb44025c2001-10-11 22:55:55 +0000346typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000347 xmlElementContentPtr cont; /* pointer to the content model subtree */
348 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000349 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000350 unsigned char depth; /* current depth in the overall tree */
351 unsigned char state; /* ROLLBACK_XXX */
352} _xmlValidState;
353
Daniel Veillardfc57b412002-04-29 15:50:14 +0000354#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000355#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
356#define CONT ctxt->vstate->cont
357#define NODE ctxt->vstate->node
358#define DEPTH ctxt->vstate->depth
359#define OCCURS ctxt->vstate->occurs
360#define STATE ctxt->vstate->state
361
Daniel Veillard5344c602001-12-31 16:37:34 +0000362#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
363#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000364
Daniel Veillard5344c602001-12-31 16:37:34 +0000365#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
366#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000367
368static int
369vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
370 xmlNodePtr node, unsigned char depth, long occurs,
371 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000372 int i = ctxt->vstateNr - 1;
373
Daniel Veillard940492d2002-04-15 10:15:25 +0000374 if (ctxt->vstateNr > MAX_RECURSE) {
375 return(-1);
376 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000377 if (ctxt->vstateTab == NULL) {
378 ctxt->vstateMax = 8;
379 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
380 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
381 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000382 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000383 return(-1);
384 }
385 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000386 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000387 xmlValidState *tmp;
388
389 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
390 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
391 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000392 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000393 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000394 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000395 ctxt->vstateMax *= 2;
396 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000397 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000398 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000399 /*
400 * Don't push on the stack a state already here
401 */
402 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
403 (ctxt->vstateTab[i].node == node) &&
404 (ctxt->vstateTab[i].depth == depth) &&
405 (ctxt->vstateTab[i].occurs == occurs) &&
406 (ctxt->vstateTab[i].state == state))
407 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000408 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
409 ctxt->vstateTab[ctxt->vstateNr].node = node;
410 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
411 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
412 ctxt->vstateTab[ctxt->vstateNr].state = state;
413 return(ctxt->vstateNr++);
414}
415
416static int
417vstateVPop(xmlValidCtxtPtr ctxt) {
418 if (ctxt->vstateNr <= 1) return(-1);
419 ctxt->vstateNr--;
420 ctxt->vstate = &ctxt->vstateTab[0];
421 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
422 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
423 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
424 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
425 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
426 return(ctxt->vstateNr);
427}
428
Daniel Veillard118aed72002-09-24 14:13:13 +0000429#endif /* LIBXML_REGEXP_ENABLED */
430
Daniel Veillard1c732d22002-11-30 11:22:59 +0000431static int
432nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
433{
434 if (ctxt->nodeMax <= 0) {
435 ctxt->nodeMax = 4;
436 ctxt->nodeTab =
437 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
438 sizeof(ctxt->nodeTab[0]));
439 if (ctxt->nodeTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000440 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000441 ctxt->nodeMax = 0;
442 return (0);
443 }
444 }
445 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000446 xmlNodePtr *tmp;
447 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
448 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
449 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000450 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000451 return (0);
452 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000453 ctxt->nodeMax *= 2;
454 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000455 }
456 ctxt->nodeTab[ctxt->nodeNr] = value;
457 ctxt->node = value;
458 return (ctxt->nodeNr++);
459}
460static xmlNodePtr
461nodeVPop(xmlValidCtxtPtr ctxt)
462{
463 xmlNodePtr ret;
464
465 if (ctxt->nodeNr <= 0)
Daniel Veillard24505b02005-07-28 23:49:35 +0000466 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +0000467 ctxt->nodeNr--;
468 if (ctxt->nodeNr > 0)
469 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
470 else
471 ctxt->node = NULL;
472 ret = ctxt->nodeTab[ctxt->nodeNr];
Daniel Veillard24505b02005-07-28 23:49:35 +0000473 ctxt->nodeTab[ctxt->nodeNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000474 return (ret);
475}
Owen Taylor3473f882001-02-23 17:55:21 +0000476
Owen Taylor3473f882001-02-23 17:55:21 +0000477#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000478static void
479xmlValidPrintNode(xmlNodePtr cur) {
480 if (cur == NULL) {
481 xmlGenericError(xmlGenericErrorContext, "null");
482 return;
483 }
484 switch (cur->type) {
485 case XML_ELEMENT_NODE:
486 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
487 break;
488 case XML_TEXT_NODE:
489 xmlGenericError(xmlGenericErrorContext, "text ");
490 break;
491 case XML_CDATA_SECTION_NODE:
492 xmlGenericError(xmlGenericErrorContext, "cdata ");
493 break;
494 case XML_ENTITY_REF_NODE:
495 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
496 break;
497 case XML_PI_NODE:
498 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
499 break;
500 case XML_COMMENT_NODE:
501 xmlGenericError(xmlGenericErrorContext, "comment ");
502 break;
503 case XML_ATTRIBUTE_NODE:
504 xmlGenericError(xmlGenericErrorContext, "?attr? ");
505 break;
506 case XML_ENTITY_NODE:
507 xmlGenericError(xmlGenericErrorContext, "?ent? ");
508 break;
509 case XML_DOCUMENT_NODE:
510 xmlGenericError(xmlGenericErrorContext, "?doc? ");
511 break;
512 case XML_DOCUMENT_TYPE_NODE:
513 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
514 break;
515 case XML_DOCUMENT_FRAG_NODE:
516 xmlGenericError(xmlGenericErrorContext, "?frag? ");
517 break;
518 case XML_NOTATION_NODE:
519 xmlGenericError(xmlGenericErrorContext, "?nota? ");
520 break;
521 case XML_HTML_DOCUMENT_NODE:
522 xmlGenericError(xmlGenericErrorContext, "?html? ");
523 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000524#ifdef LIBXML_DOCB_ENABLED
525 case XML_DOCB_DOCUMENT_NODE:
526 xmlGenericError(xmlGenericErrorContext, "?docb? ");
527 break;
528#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000529 case XML_DTD_NODE:
530 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
531 break;
532 case XML_ELEMENT_DECL:
533 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
534 break;
535 case XML_ATTRIBUTE_DECL:
536 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
537 break;
538 case XML_ENTITY_DECL:
539 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
540 break;
541 case XML_NAMESPACE_DECL:
542 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
543 break;
544 case XML_XINCLUDE_START:
545 xmlGenericError(xmlGenericErrorContext, "incstart ");
546 break;
547 case XML_XINCLUDE_END:
548 xmlGenericError(xmlGenericErrorContext, "incend ");
549 break;
550 }
551}
552
553static void
554xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000555 if (cur == NULL)
556 xmlGenericError(xmlGenericErrorContext, "null ");
557 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000558 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000559 cur = cur->next;
560 }
561}
562
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000563static void
564xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000565 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000566
567 expr[0] = 0;
568 xmlGenericError(xmlGenericErrorContext, "valid: ");
569 xmlValidPrintNodeList(cur);
570 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000571 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000572 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
573}
574
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000575static void
576xmlValidDebugState(xmlValidStatePtr state) {
577 xmlGenericError(xmlGenericErrorContext, "(");
578 if (state->cont == NULL)
579 xmlGenericError(xmlGenericErrorContext, "null,");
580 else
581 switch (state->cont->type) {
582 case XML_ELEMENT_CONTENT_PCDATA:
583 xmlGenericError(xmlGenericErrorContext, "pcdata,");
584 break;
585 case XML_ELEMENT_CONTENT_ELEMENT:
586 xmlGenericError(xmlGenericErrorContext, "%s,",
587 state->cont->name);
588 break;
589 case XML_ELEMENT_CONTENT_SEQ:
590 xmlGenericError(xmlGenericErrorContext, "seq,");
591 break;
592 case XML_ELEMENT_CONTENT_OR:
593 xmlGenericError(xmlGenericErrorContext, "or,");
594 break;
595 }
596 xmlValidPrintNode(state->node);
597 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
598 state->depth, state->occurs, state->state);
599}
600
601static void
602xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
603 int i, j;
604
605 xmlGenericError(xmlGenericErrorContext, "state: ");
606 xmlValidDebugState(ctxt->vstate);
607 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
608 ctxt->vstateNr - 1);
609 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
610 xmlValidDebugState(&ctxt->vstateTab[j]);
611 xmlGenericError(xmlGenericErrorContext, "\n");
612}
613
614/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000615#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000616 *****/
617
618#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000619#define DEBUG_VALID_MSG(m) \
620 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
621
Owen Taylor3473f882001-02-23 17:55:21 +0000622#else
623#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000624#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000625#endif
626
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000627/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000628
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000629
Owen Taylor3473f882001-02-23 17:55:21 +0000630#define CHECK_DTD \
631 if (doc == NULL) return(0); \
632 else if ((doc->intSubset == NULL) && \
633 (doc->extSubset == NULL)) return(0)
634
Owen Taylor3473f882001-02-23 17:55:21 +0000635xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
636
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000637#ifdef LIBXML_REGEXP_ENABLED
638
639/************************************************************************
640 * *
641 * Content model validation based on the regexps *
642 * *
643 ************************************************************************/
644
645/**
646 * xmlValidBuildAContentModel:
647 * @content: the content model
648 * @ctxt: the schema parser context
649 * @name: the element name whose content is being built
650 *
651 * Generate the automata sequence needed for that type
652 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000653 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000654 */
655static int
656xmlValidBuildAContentModel(xmlElementContentPtr content,
657 xmlValidCtxtPtr ctxt,
658 const xmlChar *name) {
659 if (content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000660 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
661 "Found NULL content in content model of %s\n",
662 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000663 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000664 }
665 switch (content->type) {
666 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000667 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
668 "Found PCDATA in content model of %s\n",
669 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000670 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000671 break;
672 case XML_ELEMENT_CONTENT_ELEMENT: {
673 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000674 xmlChar fn[50];
675 xmlChar *fullname;
676
677 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
678 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000679 xmlVErrMemory(ctxt, "Building content model");
Daniel Veillardc00cda82003-04-07 10:22:39 +0000680 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000681 }
682
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000683 switch (content->ocur) {
684 case XML_ELEMENT_CONTENT_ONCE:
685 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000686 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000687 break;
688 case XML_ELEMENT_CONTENT_OPT:
689 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000690 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000691 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
692 break;
693 case XML_ELEMENT_CONTENT_PLUS:
694 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000695 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000696 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000697 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000698 break;
699 case XML_ELEMENT_CONTENT_MULT:
William M. Brack8b0cbb02004-04-17 13:31:06 +0000700 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
701 ctxt->state, NULL);
702 xmlAutomataNewTransition(ctxt->am,
703 ctxt->state, ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000704 break;
705 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000706 if ((fullname != fn) && (fullname != content->name))
707 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000708 break;
709 }
710 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000711 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000712 xmlElementContentOccur ocur;
713
714 /*
715 * Simply iterate over the content
716 */
717 oldstate = ctxt->state;
718 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000719 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
720 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
721 oldstate = ctxt->state;
722 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000723 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000724 xmlValidBuildAContentModel(content->c1, ctxt, name);
725 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000726 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
727 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
728 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000729 oldend = ctxt->state;
730 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000731 switch (ocur) {
732 case XML_ELEMENT_CONTENT_ONCE:
733 break;
734 case XML_ELEMENT_CONTENT_OPT:
735 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
736 break;
737 case XML_ELEMENT_CONTENT_MULT:
738 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000739 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000740 break;
741 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000742 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000743 break;
744 }
745 break;
746 }
747 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000748 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000749 xmlElementContentOccur ocur;
750
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000751 ocur = content->ocur;
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000752 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
753 (ocur == XML_ELEMENT_CONTENT_MULT)) {
754 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
755 ctxt->state, NULL);
756 }
757 oldstate = ctxt->state;
758 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000759
760 /*
761 * iterate over the subtypes and remerge the end with an
762 * epsilon transition
763 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000764 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000765 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000766 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000767 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000768 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000769 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
770 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000771 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000772 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000773 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
774 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000775 switch (ocur) {
776 case XML_ELEMENT_CONTENT_ONCE:
777 break;
778 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000779 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000780 break;
781 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000782 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
783 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000784 break;
785 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000786 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000787 break;
788 }
789 break;
790 }
791 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000792 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
793 "ContentModel broken for element %s\n",
794 (const char *) name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000795 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000796 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000797 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000798}
799/**
800 * xmlValidBuildContentModel:
801 * @ctxt: a validation context
802 * @elem: an element declaration node
803 *
804 * (Re)Build the automata associated to the content model of this
805 * element
806 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000807 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000808 */
809int
810xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000811
812 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000813 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000814 if (elem->type != XML_ELEMENT_DECL)
815 return(0);
816 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
817 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000818 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000819 if (elem->contModel != NULL) {
820 if (!xmlRegexpIsDeterminist(elem->contModel)) {
821 ctxt->valid = 0;
822 return(0);
823 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000824 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000825 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000826
827 ctxt->am = xmlNewAutomata();
828 if (ctxt->am == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000829 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
830 XML_ERR_INTERNAL_ERROR,
831 "Cannot create automata for element %s\n",
832 elem->name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000833 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000834 }
William M. Brack78637da2003-07-31 14:47:38 +0000835 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000836 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
837 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000838 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000839 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000840 char expr[5000];
841 expr[0] = 0;
842 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000843 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
844 XML_DTD_CONTENT_NOT_DETERMINIST,
845 "Content model of %s is not determinist: %s\n",
846 elem->name, BAD_CAST expr, NULL);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000847#ifdef DEBUG_REGEXP_ALGO
848 xmlRegexpPrint(stderr, elem->contModel);
849#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000850 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000851 ctxt->state = NULL;
852 xmlFreeAutomata(ctxt->am);
853 ctxt->am = NULL;
854 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000855 }
856 ctxt->state = NULL;
857 xmlFreeAutomata(ctxt->am);
858 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000859 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000860}
861
862#endif /* LIBXML_REGEXP_ENABLED */
863
Owen Taylor3473f882001-02-23 17:55:21 +0000864/****************************************************************
865 * *
866 * Util functions for data allocation/deallocation *
867 * *
868 ****************************************************************/
869
870/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000871 * xmlNewValidCtxt:
872 *
873 * Allocate a validation context structure.
874 *
875 * Returns NULL if not, otherwise the new validation context structure
876 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000877xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000878 xmlValidCtxtPtr ret;
879
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000880 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000881 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000882 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000883 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000884
885 (void) memset(ret, 0, sizeof (xmlValidCtxt));
886
887 return (ret);
888}
889
890/**
891 * xmlFreeValidCtxt:
892 * @cur: the validation context to free
893 *
894 * Free a validation context structure.
895 */
896void
897xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
Daniel Veillardc0be74b2004-11-03 19:16:55 +0000898 if (cur->vstateTab != NULL)
899 xmlFree(cur->vstateTab);
900 if (cur->nodeTab != NULL)
901 xmlFree(cur->nodeTab);
Daniel Veillarda37aab82003-06-09 09:10:36 +0000902 xmlFree(cur);
903}
904
Daniel Veillard4432df22003-09-28 18:58:27 +0000905#endif /* LIBXML_VALID_ENABLED */
906
Daniel Veillarda37aab82003-06-09 09:10:36 +0000907/**
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000908 * xmlNewDocElementContent:
909 * @doc: the document
Owen Taylor3473f882001-02-23 17:55:21 +0000910 * @name: the subelement name or NULL
911 * @type: the type of element content decl
912 *
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000913 * Allocate an element content structure for the document.
Owen Taylor3473f882001-02-23 17:55:21 +0000914 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000915 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000916 */
917xmlElementContentPtr
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000918xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
919 xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000920 xmlElementContentPtr ret;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000921 xmlDictPtr dict = NULL;
922
923 if (doc != NULL)
924 dict = doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +0000925
926 switch(type) {
927 case XML_ELEMENT_CONTENT_ELEMENT:
928 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000929 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
930 "xmlNewElementContent : name == NULL !\n",
931 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000932 }
933 break;
934 case XML_ELEMENT_CONTENT_PCDATA:
935 case XML_ELEMENT_CONTENT_SEQ:
936 case XML_ELEMENT_CONTENT_OR:
937 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000938 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
939 "xmlNewElementContent : name != NULL !\n",
940 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000941 }
942 break;
943 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000944 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
945 "Internal: ELEMENT content corrupted invalid type\n",
946 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000947 return(NULL);
948 }
949 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
950 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000951 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000952 return(NULL);
953 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000954 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000955 ret->type = type;
956 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000957 if (name != NULL) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000958 int l;
959 const xmlChar *tmp;
960
961 tmp = xmlSplitQName3(name, &l);
962 if (tmp == NULL) {
963 if (dict == NULL)
964 ret->name = xmlStrdup(name);
965 else
966 ret->name = xmlDictLookup(dict, name, -1);
967 } else {
968 if (dict == NULL) {
969 ret->prefix = xmlStrndup(name, l);
970 ret->name = xmlStrdup(tmp);
971 } else {
972 ret->prefix = xmlDictLookup(dict, name, l);
973 ret->name = xmlDictLookup(dict, tmp, -1);
974 }
975 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000976 }
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000977 return(ret);
978}
979
980/**
981 * xmlNewElementContent:
982 * @name: the subelement name or NULL
983 * @type: the type of element content decl
984 *
985 * Allocate an element content structure.
986 * Deprecated in favor of xmlNewDocElementContent
987 *
988 * Returns NULL if not, otherwise the new element content structure
989 */
990xmlElementContentPtr
991xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
992 return(xmlNewDocElementContent(NULL, name, type));
993}
994
995/**
996 * xmlCopyDocElementContent:
997 * @doc: the document owning the element declaration
998 * @cur: An element content pointer.
999 *
1000 * Build a copy of an element content description.
1001 *
1002 * Returns the new xmlElementContentPtr or NULL in case of error.
1003 */
1004xmlElementContentPtr
1005xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1006 xmlElementContentPtr ret = NULL, prev = NULL, tmp;
1007 xmlDictPtr dict = NULL;
1008
1009 if (cur == NULL) return(NULL);
1010
1011 if (doc != NULL)
1012 dict = doc->dict;
1013
1014 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1015 if (ret == NULL) {
1016 xmlVErrMemory(NULL, "malloc failed");
1017 return(NULL);
1018 }
1019 memset(ret, 0, sizeof(xmlElementContent));
1020 ret->type = cur->type;
1021 ret->ocur = cur->ocur;
1022 if (cur->name != NULL) {
1023 if (dict)
1024 ret->name = xmlDictLookup(dict, cur->name, -1);
1025 else
1026 ret->name = xmlStrdup(cur->name);
1027 }
1028
1029 if (cur->prefix != NULL) {
1030 if (dict)
1031 ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1032 else
1033 ret->prefix = xmlStrdup(cur->prefix);
1034 }
1035 if (cur->c1 != NULL)
1036 ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1037 if (ret->c1 != NULL)
1038 ret->c1->parent = ret;
1039 if (cur->c2 != NULL) {
1040 prev = ret;
1041 cur = cur->c2;
1042 while (cur != NULL) {
1043 tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1044 if (tmp == NULL) {
1045 xmlVErrMemory(NULL, "malloc failed");
1046 return(ret);
1047 }
1048 memset(tmp, 0, sizeof(xmlElementContent));
1049 tmp->type = cur->type;
1050 tmp->ocur = cur->ocur;
1051 prev->c2 = tmp;
1052 if (cur->name != NULL) {
1053 if (dict)
1054 tmp->name = xmlDictLookup(dict, cur->name, -1);
1055 else
1056 tmp->name = xmlStrdup(cur->name);
1057 }
1058
1059 if (cur->prefix != NULL) {
1060 if (dict)
1061 tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1062 else
1063 tmp->prefix = xmlStrdup(cur->prefix);
1064 }
1065 if (cur->c1 != NULL)
1066 tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1067 if (tmp->c1 != NULL)
1068 tmp->c1->parent = ret;
1069 prev = tmp;
1070 cur = cur->c2;
1071 }
1072 }
Owen Taylor3473f882001-02-23 17:55:21 +00001073 return(ret);
1074}
1075
1076/**
1077 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +00001078 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +00001079 *
1080 * Build a copy of an element content description.
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001081 * Deprecated, use xmlCopyDocElementContent instead
Owen Taylor3473f882001-02-23 17:55:21 +00001082 *
1083 * Returns the new xmlElementContentPtr or NULL in case of error.
1084 */
1085xmlElementContentPtr
1086xmlCopyElementContent(xmlElementContentPtr cur) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001087 return(xmlCopyDocElementContent(NULL, cur));
1088}
Owen Taylor3473f882001-02-23 17:55:21 +00001089
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001090/**
1091 * xmlFreeDocElementContent:
1092 * @doc: the document owning the element declaration
1093 * @cur: the element content tree to free
1094 *
1095 * Free an element content structure. The whole subtree is removed.
1096 */
1097void
1098xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1099 xmlElementContentPtr next;
1100 xmlDictPtr dict = NULL;
1101
1102 if (doc != NULL)
1103 dict = doc->dict;
1104
1105 while (cur != NULL) {
1106 next = cur->c2;
1107 switch (cur->type) {
1108 case XML_ELEMENT_CONTENT_PCDATA:
1109 case XML_ELEMENT_CONTENT_ELEMENT:
1110 case XML_ELEMENT_CONTENT_SEQ:
1111 case XML_ELEMENT_CONTENT_OR:
1112 break;
1113 default:
1114 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1115 "Internal: ELEMENT content corrupted invalid type\n",
1116 NULL);
1117 return;
1118 }
1119 if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1);
1120 if (dict) {
1121 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1122 xmlFree((xmlChar *) cur->name);
1123 if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1124 xmlFree((xmlChar *) cur->prefix);
1125 } else {
1126 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1127 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1128 }
1129 xmlFree(cur);
1130 cur = next;
Owen Taylor3473f882001-02-23 17:55:21 +00001131 }
Owen Taylor3473f882001-02-23 17:55:21 +00001132}
1133
1134/**
1135 * xmlFreeElementContent:
1136 * @cur: the element content tree to free
1137 *
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001138 * Free an element content structure. The whole subtree is removed.
1139 * Deprecated, use xmlFreeDocElementContent instead
Owen Taylor3473f882001-02-23 17:55:21 +00001140 */
1141void
1142xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001143 xmlFreeDocElementContent(NULL, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001144}
1145
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001146#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001147/**
1148 * xmlDumpElementContent:
1149 * @buf: An XML buffer
1150 * @content: An element table
1151 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1152 *
1153 * This will dump the content of the element table as an XML DTD definition
1154 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001155static void
Owen Taylor3473f882001-02-23 17:55:21 +00001156xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1157 if (content == NULL) return;
1158
1159 if (glob) xmlBufferWriteChar(buf, "(");
1160 switch (content->type) {
1161 case XML_ELEMENT_CONTENT_PCDATA:
1162 xmlBufferWriteChar(buf, "#PCDATA");
1163 break;
1164 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001165 if (content->prefix != NULL) {
1166 xmlBufferWriteCHAR(buf, content->prefix);
1167 xmlBufferWriteChar(buf, ":");
1168 }
Owen Taylor3473f882001-02-23 17:55:21 +00001169 xmlBufferWriteCHAR(buf, content->name);
1170 break;
1171 case XML_ELEMENT_CONTENT_SEQ:
1172 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1173 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1174 xmlDumpElementContent(buf, content->c1, 1);
1175 else
1176 xmlDumpElementContent(buf, content->c1, 0);
1177 xmlBufferWriteChar(buf, " , ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001178 if ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1179 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
1180 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001181 xmlDumpElementContent(buf, content->c2, 1);
1182 else
1183 xmlDumpElementContent(buf, content->c2, 0);
1184 break;
1185 case XML_ELEMENT_CONTENT_OR:
1186 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1187 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1188 xmlDumpElementContent(buf, content->c1, 1);
1189 else
1190 xmlDumpElementContent(buf, content->c1, 0);
1191 xmlBufferWriteChar(buf, " | ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001192 if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1193 ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
1194 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001195 xmlDumpElementContent(buf, content->c2, 1);
1196 else
1197 xmlDumpElementContent(buf, content->c2, 0);
1198 break;
1199 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001200 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1201 "Internal: ELEMENT content corrupted invalid type\n",
1202 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001203 }
1204 if (glob)
1205 xmlBufferWriteChar(buf, ")");
1206 switch (content->ocur) {
1207 case XML_ELEMENT_CONTENT_ONCE:
1208 break;
1209 case XML_ELEMENT_CONTENT_OPT:
1210 xmlBufferWriteChar(buf, "?");
1211 break;
1212 case XML_ELEMENT_CONTENT_MULT:
1213 xmlBufferWriteChar(buf, "*");
1214 break;
1215 case XML_ELEMENT_CONTENT_PLUS:
1216 xmlBufferWriteChar(buf, "+");
1217 break;
1218 }
1219}
1220
1221/**
1222 * xmlSprintfElementContent:
1223 * @buf: an output buffer
1224 * @content: An element table
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001225 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001226 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001227 * Deprecated, unsafe, use xmlSnprintfElementContent
1228 */
1229void
1230xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1231 xmlElementContentPtr content ATTRIBUTE_UNUSED,
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001232 int englob ATTRIBUTE_UNUSED) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001233}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001234#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001235
1236/**
1237 * xmlSnprintfElementContent:
1238 * @buf: an output buffer
1239 * @size: the buffer size
1240 * @content: An element table
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001241 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
Daniel Veillardd3d06722001-08-15 12:06:36 +00001242 *
Owen Taylor3473f882001-02-23 17:55:21 +00001243 * This will dump the content of the element content definition
1244 * Intended just for the debug routine
1245 */
1246void
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001247xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001248 int len;
1249
Owen Taylor3473f882001-02-23 17:55:21 +00001250 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001251 len = strlen(buf);
1252 if (size - len < 50) {
1253 if ((size - len > 4) && (buf[len - 1] != '.'))
1254 strcat(buf, " ...");
1255 return;
1256 }
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001257 if (englob) strcat(buf, "(");
Owen Taylor3473f882001-02-23 17:55:21 +00001258 switch (content->type) {
1259 case XML_ELEMENT_CONTENT_PCDATA:
1260 strcat(buf, "#PCDATA");
1261 break;
1262 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001263 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001264 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001265 strcat(buf, " ...");
1266 return;
1267 }
1268 strcat(buf, (char *) content->prefix);
1269 strcat(buf, ":");
1270 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001271 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001272 strcat(buf, " ...");
1273 return;
1274 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001275 if (content->name != NULL)
1276 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001277 break;
1278 case XML_ELEMENT_CONTENT_SEQ:
1279 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1280 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001281 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001282 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001283 xmlSnprintfElementContent(buf, size, content->c1, 0);
1284 len = strlen(buf);
1285 if (size - len < 50) {
1286 if ((size - len > 4) && (buf[len - 1] != '.'))
1287 strcat(buf, " ...");
1288 return;
1289 }
Owen Taylor3473f882001-02-23 17:55:21 +00001290 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001291 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1292 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1293 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001294 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001295 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001296 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001297 break;
1298 case XML_ELEMENT_CONTENT_OR:
1299 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1300 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001301 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001302 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001303 xmlSnprintfElementContent(buf, size, content->c1, 0);
1304 len = strlen(buf);
1305 if (size - len < 50) {
1306 if ((size - len > 4) && (buf[len - 1] != '.'))
1307 strcat(buf, " ...");
1308 return;
1309 }
Owen Taylor3473f882001-02-23 17:55:21 +00001310 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001311 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1312 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1313 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001314 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001315 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001316 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001317 break;
1318 }
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001319 if (englob)
Owen Taylor3473f882001-02-23 17:55:21 +00001320 strcat(buf, ")");
1321 switch (content->ocur) {
1322 case XML_ELEMENT_CONTENT_ONCE:
1323 break;
1324 case XML_ELEMENT_CONTENT_OPT:
1325 strcat(buf, "?");
1326 break;
1327 case XML_ELEMENT_CONTENT_MULT:
1328 strcat(buf, "*");
1329 break;
1330 case XML_ELEMENT_CONTENT_PLUS:
1331 strcat(buf, "+");
1332 break;
1333 }
1334}
1335
1336/****************************************************************
1337 * *
1338 * Registration of DTD declarations *
1339 * *
1340 ****************************************************************/
1341
1342/**
Owen Taylor3473f882001-02-23 17:55:21 +00001343 * xmlFreeElement:
1344 * @elem: An element
1345 *
1346 * Deallocate the memory used by an element definition
1347 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001348static void
Owen Taylor3473f882001-02-23 17:55:21 +00001349xmlFreeElement(xmlElementPtr elem) {
1350 if (elem == NULL) return;
1351 xmlUnlinkNode((xmlNodePtr) elem);
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001352 xmlFreeDocElementContent(elem->doc, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001353 if (elem->name != NULL)
1354 xmlFree((xmlChar *) elem->name);
1355 if (elem->prefix != NULL)
1356 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001357#ifdef LIBXML_REGEXP_ENABLED
1358 if (elem->contModel != NULL)
1359 xmlRegFreeRegexp(elem->contModel);
1360#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001361 xmlFree(elem);
1362}
1363
1364
1365/**
1366 * xmlAddElementDecl:
1367 * @ctxt: the validation context
1368 * @dtd: pointer to the DTD
1369 * @name: the entity name
1370 * @type: the element type
1371 * @content: the element content tree or NULL
1372 *
1373 * Register a new element declaration
1374 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001375 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001376 */
1377xmlElementPtr
William M. Brackedb65a72004-02-06 07:36:04 +00001378xmlAddElementDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001379 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001380 xmlElementTypeVal type,
1381 xmlElementContentPtr content) {
1382 xmlElementPtr ret;
1383 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001384 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001385 xmlChar *ns, *uqname;
1386
1387 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001388 return(NULL);
1389 }
1390 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001391 return(NULL);
1392 }
Daniel Veillard316a5c32005-01-23 22:56:39 +00001393
Owen Taylor3473f882001-02-23 17:55:21 +00001394 switch (type) {
1395 case XML_ELEMENT_TYPE_EMPTY:
1396 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001397 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1398 "xmlAddElementDecl: content != NULL for EMPTY\n",
1399 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001400 return(NULL);
1401 }
1402 break;
1403 case XML_ELEMENT_TYPE_ANY:
1404 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001405 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1406 "xmlAddElementDecl: content != NULL for ANY\n",
1407 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001408 return(NULL);
1409 }
1410 break;
1411 case XML_ELEMENT_TYPE_MIXED:
1412 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001413 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1414 "xmlAddElementDecl: content == NULL for MIXED\n",
1415 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001416 return(NULL);
1417 }
1418 break;
1419 case XML_ELEMENT_TYPE_ELEMENT:
1420 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001421 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1422 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1423 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001424 return(NULL);
1425 }
1426 break;
1427 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001428 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1429 "Internal: ELEMENT decl corrupted invalid type\n",
1430 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001431 return(NULL);
1432 }
1433
1434 /*
1435 * check if name is a QName
1436 */
1437 uqname = xmlSplitQName2(name, &ns);
1438 if (uqname != NULL)
1439 name = uqname;
1440
1441 /*
1442 * Create the Element table if needed.
1443 */
1444 table = (xmlElementTablePtr) dtd->elements;
1445 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00001446 xmlDictPtr dict = NULL;
1447
1448 if (dtd->doc != NULL)
1449 dict = dtd->doc->dict;
1450 table = xmlHashCreateDict(0, dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001451 dtd->elements = (void *) table;
1452 }
1453 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001454 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001455 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001456 if (uqname != NULL)
1457 xmlFree(uqname);
1458 if (ns != NULL)
1459 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001460 return(NULL);
1461 }
1462
Daniel Veillarda10efa82001-04-18 13:09:01 +00001463 /*
1464 * lookup old attributes inserted on an undefined element in the
1465 * internal subset.
1466 */
1467 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1468 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1469 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1470 oldAttributes = ret->attributes;
1471 ret->attributes = NULL;
1472 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1473 xmlFreeElement(ret);
1474 }
Owen Taylor3473f882001-02-23 17:55:21 +00001475 }
Owen Taylor3473f882001-02-23 17:55:21 +00001476
1477 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001478 * The element may already be present if one of its attribute
1479 * was registered first
1480 */
1481 ret = xmlHashLookup2(table, name, ns);
1482 if (ret != NULL) {
1483 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001484#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001485 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001486 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001487 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001488 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1489 "Redefinition of element %s\n",
1490 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001491#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001492 if (uqname != NULL)
1493 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001494 if (ns != NULL)
1495 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001496 return(NULL);
1497 }
William M. Brackd6e347e2005-04-15 01:34:41 +00001498 if (ns != NULL) {
1499 xmlFree(ns);
1500 ns = NULL;
1501 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001502 } else {
1503 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1504 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001505 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001506 if (uqname != NULL)
1507 xmlFree(uqname);
1508 if (ns != NULL)
1509 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001510 return(NULL);
1511 }
1512 memset(ret, 0, sizeof(xmlElement));
1513 ret->type = XML_ELEMENT_DECL;
1514
1515 /*
1516 * fill the structure.
1517 */
1518 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001519 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001520 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001521 if (uqname != NULL)
1522 xmlFree(uqname);
1523 if (ns != NULL)
1524 xmlFree(ns);
1525 xmlFree(ret);
1526 return(NULL);
1527 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001528 ret->prefix = ns;
1529
1530 /*
1531 * Validity Check:
1532 * Insertion must not fail
1533 */
1534 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001535#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001536 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001537 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001538 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001539 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1540 "Redefinition of element %s\n",
1541 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001542#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001543 xmlFreeElement(ret);
1544 if (uqname != NULL)
1545 xmlFree(uqname);
1546 return(NULL);
1547 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001548 /*
1549 * For new element, may have attributes from earlier
1550 * definition in internal subset
1551 */
1552 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001553 }
1554
1555 /*
1556 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001557 */
1558 ret->etype = type;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001559 /*
1560 * Avoid a stupid copy when called by the parser
1561 * and flag it by setting a special parent value
1562 * so the parser doesn't unallocate it.
1563 */
Daniel Veillardc394f732005-01-26 00:04:52 +00001564 if ((ctxt != NULL) &&
1565 ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
1566 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001567 ret->content = content;
1568 if (content != NULL)
1569 content->parent = (xmlElementContentPtr) 1;
1570 } else {
1571 ret->content = xmlCopyDocElementContent(dtd->doc, content);
1572 }
Owen Taylor3473f882001-02-23 17:55:21 +00001573
1574 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001575 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001576 */
1577 ret->parent = dtd;
1578 ret->doc = dtd->doc;
1579 if (dtd->last == NULL) {
1580 dtd->children = dtd->last = (xmlNodePtr) ret;
1581 } else {
1582 dtd->last->next = (xmlNodePtr) ret;
1583 ret->prev = dtd->last;
1584 dtd->last = (xmlNodePtr) ret;
1585 }
1586 if (uqname != NULL)
1587 xmlFree(uqname);
1588 return(ret);
1589}
1590
1591/**
1592 * xmlFreeElementTable:
1593 * @table: An element table
1594 *
1595 * Deallocate the memory used by an element hash table.
1596 */
1597void
1598xmlFreeElementTable(xmlElementTablePtr table) {
1599 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1600}
1601
Daniel Veillard652327a2003-09-29 18:02:38 +00001602#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001603/**
1604 * xmlCopyElement:
1605 * @elem: An element
1606 *
1607 * Build a copy of an element.
1608 *
1609 * Returns the new xmlElementPtr or NULL in case of error.
1610 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001611static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001612xmlCopyElement(xmlElementPtr elem) {
1613 xmlElementPtr cur;
1614
1615 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1616 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001617 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001618 return(NULL);
1619 }
1620 memset(cur, 0, sizeof(xmlElement));
1621 cur->type = XML_ELEMENT_DECL;
1622 cur->etype = elem->etype;
1623 if (elem->name != NULL)
1624 cur->name = xmlStrdup(elem->name);
1625 else
1626 cur->name = NULL;
1627 if (elem->prefix != NULL)
1628 cur->prefix = xmlStrdup(elem->prefix);
1629 else
1630 cur->prefix = NULL;
1631 cur->content = xmlCopyElementContent(elem->content);
1632 /* TODO : rebuild the attribute list on the copy */
1633 cur->attributes = NULL;
1634 return(cur);
1635}
1636
1637/**
1638 * xmlCopyElementTable:
1639 * @table: An element table
1640 *
1641 * Build a copy of an element table.
1642 *
1643 * Returns the new xmlElementTablePtr or NULL in case of error.
1644 */
1645xmlElementTablePtr
1646xmlCopyElementTable(xmlElementTablePtr table) {
1647 return((xmlElementTablePtr) xmlHashCopy(table,
1648 (xmlHashCopier) xmlCopyElement));
1649}
Daniel Veillard652327a2003-09-29 18:02:38 +00001650#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001651
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001652#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001653/**
1654 * xmlDumpElementDecl:
1655 * @buf: the XML buffer output
1656 * @elem: An element table
1657 *
1658 * This will dump the content of the element declaration as an XML
1659 * DTD definition
1660 */
1661void
1662xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001663 if ((buf == NULL) || (elem == NULL))
1664 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001665 switch (elem->etype) {
1666 case XML_ELEMENT_TYPE_EMPTY:
1667 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001668 if (elem->prefix != NULL) {
1669 xmlBufferWriteCHAR(buf, elem->prefix);
1670 xmlBufferWriteChar(buf, ":");
1671 }
Owen Taylor3473f882001-02-23 17:55:21 +00001672 xmlBufferWriteCHAR(buf, elem->name);
1673 xmlBufferWriteChar(buf, " EMPTY>\n");
1674 break;
1675 case XML_ELEMENT_TYPE_ANY:
1676 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001677 if (elem->prefix != NULL) {
1678 xmlBufferWriteCHAR(buf, elem->prefix);
1679 xmlBufferWriteChar(buf, ":");
1680 }
Owen Taylor3473f882001-02-23 17:55:21 +00001681 xmlBufferWriteCHAR(buf, elem->name);
1682 xmlBufferWriteChar(buf, " ANY>\n");
1683 break;
1684 case XML_ELEMENT_TYPE_MIXED:
1685 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001686 if (elem->prefix != NULL) {
1687 xmlBufferWriteCHAR(buf, elem->prefix);
1688 xmlBufferWriteChar(buf, ":");
1689 }
Owen Taylor3473f882001-02-23 17:55:21 +00001690 xmlBufferWriteCHAR(buf, elem->name);
1691 xmlBufferWriteChar(buf, " ");
1692 xmlDumpElementContent(buf, elem->content, 1);
1693 xmlBufferWriteChar(buf, ">\n");
1694 break;
1695 case XML_ELEMENT_TYPE_ELEMENT:
1696 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001697 if (elem->prefix != NULL) {
1698 xmlBufferWriteCHAR(buf, elem->prefix);
1699 xmlBufferWriteChar(buf, ":");
1700 }
Owen Taylor3473f882001-02-23 17:55:21 +00001701 xmlBufferWriteCHAR(buf, elem->name);
1702 xmlBufferWriteChar(buf, " ");
1703 xmlDumpElementContent(buf, elem->content, 1);
1704 xmlBufferWriteChar(buf, ">\n");
1705 break;
1706 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001707 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1708 "Internal: ELEMENT struct corrupted invalid type\n",
1709 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001710 }
1711}
1712
1713/**
William M. Brack9e660592003-10-20 14:56:06 +00001714 * xmlDumpElementDeclScan:
1715 * @elem: An element table
1716 * @buf: the XML buffer output
1717 *
1718 * This routine is used by the hash scan function. It just reverses
1719 * the arguments.
1720 */
1721static void
1722xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1723 xmlDumpElementDecl(buf, elem);
1724}
1725
1726/**
Owen Taylor3473f882001-02-23 17:55:21 +00001727 * xmlDumpElementTable:
1728 * @buf: the XML buffer output
1729 * @table: An element table
1730 *
1731 * This will dump the content of the element table as an XML DTD definition
1732 */
1733void
1734xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001735 if ((buf == NULL) || (table == NULL))
1736 return;
William M. Brack9e660592003-10-20 14:56:06 +00001737 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001738}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001739#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001740
1741/**
1742 * xmlCreateEnumeration:
1743 * @name: the enumeration name or NULL
1744 *
1745 * create and initialize an enumeration attribute node.
1746 *
1747 * Returns the xmlEnumerationPtr just created or NULL in case
1748 * of error.
1749 */
1750xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001751xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001752 xmlEnumerationPtr ret;
1753
1754 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1755 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001756 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001757 return(NULL);
1758 }
1759 memset(ret, 0, sizeof(xmlEnumeration));
1760
1761 if (name != NULL)
1762 ret->name = xmlStrdup(name);
1763 return(ret);
1764}
1765
1766/**
1767 * xmlFreeEnumeration:
1768 * @cur: the tree to free.
1769 *
1770 * free an enumeration attribute node (recursive).
1771 */
1772void
1773xmlFreeEnumeration(xmlEnumerationPtr cur) {
1774 if (cur == NULL) return;
1775
1776 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1777
1778 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001779 xmlFree(cur);
1780}
1781
Daniel Veillard652327a2003-09-29 18:02:38 +00001782#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001783/**
1784 * xmlCopyEnumeration:
1785 * @cur: the tree to copy.
1786 *
1787 * Copy an enumeration attribute node (recursive).
1788 *
1789 * Returns the xmlEnumerationPtr just created or NULL in case
1790 * of error.
1791 */
1792xmlEnumerationPtr
1793xmlCopyEnumeration(xmlEnumerationPtr cur) {
1794 xmlEnumerationPtr ret;
1795
1796 if (cur == NULL) return(NULL);
1797 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1798
1799 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1800 else ret->next = NULL;
1801
1802 return(ret);
1803}
Daniel Veillard652327a2003-09-29 18:02:38 +00001804#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001805
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001806#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001807/**
1808 * xmlDumpEnumeration:
1809 * @buf: the XML buffer output
1810 * @enum: An enumeration
1811 *
1812 * This will dump the content of the enumeration
1813 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001814static void
Owen Taylor3473f882001-02-23 17:55:21 +00001815xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001816 if ((buf == NULL) || (cur == NULL))
1817 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001818
1819 xmlBufferWriteCHAR(buf, cur->name);
1820 if (cur->next == NULL)
1821 xmlBufferWriteChar(buf, ")");
1822 else {
1823 xmlBufferWriteChar(buf, " | ");
1824 xmlDumpEnumeration(buf, cur->next);
1825 }
1826}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001827#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001828
Daniel Veillard4432df22003-09-28 18:58:27 +00001829#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001830/**
1831 * xmlScanAttributeDeclCallback:
1832 * @attr: the attribute decl
1833 * @list: the list to update
1834 *
1835 * Callback called by xmlScanAttributeDecl when a new attribute
1836 * has to be entered in the list.
1837 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001838static void
Owen Taylor3473f882001-02-23 17:55:21 +00001839xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001840 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001841 attr->nexth = *list;
1842 *list = attr;
1843}
1844
1845/**
1846 * xmlScanAttributeDecl:
1847 * @dtd: pointer to the DTD
1848 * @elem: the element name
1849 *
1850 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001851 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001852 *
1853 * Returns the pointer to the first attribute decl in the chain,
1854 * possibly NULL.
1855 */
1856xmlAttributePtr
1857xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1858 xmlAttributePtr ret = NULL;
1859 xmlAttributeTablePtr table;
1860
1861 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001862 return(NULL);
1863 }
1864 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001865 return(NULL);
1866 }
1867 table = (xmlAttributeTablePtr) dtd->attributes;
1868 if (table == NULL)
1869 return(NULL);
1870
1871 /* WRONG !!! */
1872 xmlHashScan3(table, NULL, NULL, elem,
1873 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1874 return(ret);
1875}
1876
1877/**
1878 * xmlScanIDAttributeDecl:
1879 * @ctxt: the validation context
1880 * @elem: the element name
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001881 * @err: whether to raise errors here
Owen Taylor3473f882001-02-23 17:55:21 +00001882 *
1883 * Verify that the element don't have too many ID attributes
1884 * declared.
1885 *
1886 * Returns the number of ID attributes found.
1887 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001888static int
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001889xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
Owen Taylor3473f882001-02-23 17:55:21 +00001890 xmlAttributePtr cur;
1891 int ret = 0;
1892
1893 if (elem == NULL) return(0);
1894 cur = elem->attributes;
1895 while (cur != NULL) {
1896 if (cur->atype == XML_ATTRIBUTE_ID) {
1897 ret ++;
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001898 if ((ret > 1) && (err))
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001899 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001900 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001901 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001902 }
1903 cur = cur->nexth;
1904 }
1905 return(ret);
1906}
Daniel Veillard4432df22003-09-28 18:58:27 +00001907#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001908
1909/**
1910 * xmlFreeAttribute:
1911 * @elem: An attribute
1912 *
1913 * Deallocate the memory used by an attribute definition
1914 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001915static void
Owen Taylor3473f882001-02-23 17:55:21 +00001916xmlFreeAttribute(xmlAttributePtr attr) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001917 xmlDictPtr dict;
1918
Owen Taylor3473f882001-02-23 17:55:21 +00001919 if (attr == NULL) return;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001920 if (attr->doc != NULL)
1921 dict = attr->doc->dict;
1922 else
1923 dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001924 xmlUnlinkNode((xmlNodePtr) attr);
1925 if (attr->tree != NULL)
1926 xmlFreeEnumeration(attr->tree);
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001927 if (dict) {
1928 if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1929 xmlFree((xmlChar *) attr->elem);
1930 if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1931 xmlFree((xmlChar *) attr->name);
1932 if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1933 xmlFree((xmlChar *) attr->prefix);
1934 if ((attr->defaultValue != NULL) &&
1935 (!xmlDictOwns(dict, attr->defaultValue)))
1936 xmlFree((xmlChar *) attr->defaultValue);
1937 } else {
1938 if (attr->elem != NULL)
1939 xmlFree((xmlChar *) attr->elem);
1940 if (attr->name != NULL)
1941 xmlFree((xmlChar *) attr->name);
1942 if (attr->defaultValue != NULL)
1943 xmlFree((xmlChar *) attr->defaultValue);
1944 if (attr->prefix != NULL)
1945 xmlFree((xmlChar *) attr->prefix);
1946 }
Owen Taylor3473f882001-02-23 17:55:21 +00001947 xmlFree(attr);
1948}
1949
1950
1951/**
1952 * xmlAddAttributeDecl:
1953 * @ctxt: the validation context
1954 * @dtd: pointer to the DTD
1955 * @elem: the element name
1956 * @name: the attribute name
1957 * @ns: the attribute namespace prefix
1958 * @type: the attribute type
1959 * @def: the attribute default type
1960 * @defaultValue: the attribute default value
1961 * @tree: if it's an enumeration, the associated list
1962 *
1963 * Register a new attribute declaration
1964 * Note that @tree becomes the ownership of the DTD
1965 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001966 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001967 */
1968xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001969xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001970 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001971 const xmlChar *name, const xmlChar *ns,
1972 xmlAttributeType type, xmlAttributeDefault def,
1973 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1974 xmlAttributePtr ret;
1975 xmlAttributeTablePtr table;
1976 xmlElementPtr elemDef;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001977 xmlDictPtr dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001978
1979 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001980 xmlFreeEnumeration(tree);
1981 return(NULL);
1982 }
1983 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001984 xmlFreeEnumeration(tree);
1985 return(NULL);
1986 }
1987 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001988 xmlFreeEnumeration(tree);
1989 return(NULL);
1990 }
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001991 if (dtd->doc != NULL)
1992 dict = dtd->doc->dict;
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001993
Daniel Veillard4432df22003-09-28 18:58:27 +00001994#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001995 /*
1996 * Check the type and possibly the default value.
1997 */
1998 switch (type) {
1999 case XML_ATTRIBUTE_CDATA:
2000 break;
2001 case XML_ATTRIBUTE_ID:
2002 break;
2003 case XML_ATTRIBUTE_IDREF:
2004 break;
2005 case XML_ATTRIBUTE_IDREFS:
2006 break;
2007 case XML_ATTRIBUTE_ENTITY:
2008 break;
2009 case XML_ATTRIBUTE_ENTITIES:
2010 break;
2011 case XML_ATTRIBUTE_NMTOKEN:
2012 break;
2013 case XML_ATTRIBUTE_NMTOKENS:
2014 break;
2015 case XML_ATTRIBUTE_ENUMERATION:
2016 break;
2017 case XML_ATTRIBUTE_NOTATION:
2018 break;
2019 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002020 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
2021 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2022 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002023 xmlFreeEnumeration(tree);
2024 return(NULL);
2025 }
2026 if ((defaultValue != NULL) &&
2027 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002028 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
2029 "Attribute %s of %s: invalid default value\n",
2030 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00002031 defaultValue = NULL;
Daniel Veillard42595322004-11-08 10:52:06 +00002032 if (ctxt != NULL)
2033 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002034 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002035#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002036
2037 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00002038 * Check first that an attribute defined in the external subset wasn't
2039 * already defined in the internal subset
2040 */
2041 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2042 (dtd->doc->intSubset != NULL) &&
2043 (dtd->doc->intSubset->attributes != NULL)) {
2044 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2045 if (ret != NULL)
2046 return(NULL);
2047 }
2048
2049 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002050 * Create the Attribute table if needed.
2051 */
2052 table = (xmlAttributeTablePtr) dtd->attributes;
2053 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00002054 table = xmlHashCreateDict(0, dict);
Owen Taylor3473f882001-02-23 17:55:21 +00002055 dtd->attributes = (void *) table;
2056 }
2057 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002058 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002059 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002060 return(NULL);
2061 }
2062
2063
2064 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2065 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002066 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002067 return(NULL);
2068 }
2069 memset(ret, 0, sizeof(xmlAttribute));
2070 ret->type = XML_ATTRIBUTE_DECL;
2071
2072 /*
2073 * fill the structure.
2074 */
2075 ret->atype = type;
William M. Brackf810de02005-07-06 22:48:41 +00002076 /*
2077 * doc must be set before possible error causes call
2078 * to xmlFreeAttribute (because it's used to check on
2079 * dict use)
2080 */
2081 ret->doc = dtd->doc;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002082 if (dict) {
2083 ret->name = xmlDictLookup(dict, name, -1);
2084 ret->prefix = xmlDictLookup(dict, ns, -1);
2085 ret->elem = xmlDictLookup(dict, elem, -1);
2086 } else {
2087 ret->name = xmlStrdup(name);
2088 ret->prefix = xmlStrdup(ns);
2089 ret->elem = xmlStrdup(elem);
2090 }
Owen Taylor3473f882001-02-23 17:55:21 +00002091 ret->def = def;
2092 ret->tree = tree;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002093 if (defaultValue != NULL) {
2094 if (dict)
2095 ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2096 else
2097 ret->defaultValue = xmlStrdup(defaultValue);
2098 }
Owen Taylor3473f882001-02-23 17:55:21 +00002099
2100 /*
2101 * Validity Check:
2102 * Search the DTD for previous declarations of the ATTLIST
2103 */
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002104 if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002105#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002106 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002107 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002108 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002109 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00002110 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002111 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00002112#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002113 xmlFreeAttribute(ret);
2114 return(NULL);
2115 }
2116
2117 /*
2118 * Validity Check:
2119 * Multiple ID per element
2120 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00002121 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002122 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00002123
Daniel Veillard4432df22003-09-28 18:58:27 +00002124#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002125 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillarddbee0f12005-06-27 13:42:57 +00002126 (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002127 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00002128 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002129 elem, name, NULL);
Daniel Veillard42595322004-11-08 10:52:06 +00002130 if (ctxt != NULL)
2131 ctxt->valid = 0;
Daniel Veillardc7612992002-02-17 22:47:37 +00002132 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002133#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00002134
Daniel Veillard48da9102001-08-07 01:10:10 +00002135 /*
2136 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002137 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00002138 */
2139 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2140 ((ret->prefix != NULL &&
2141 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2142 ret->nexth = elemDef->attributes;
2143 elemDef->attributes = ret;
2144 } else {
2145 xmlAttributePtr tmp = elemDef->attributes;
2146
2147 while ((tmp != NULL) &&
2148 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2149 ((ret->prefix != NULL &&
2150 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2151 if (tmp->nexth == NULL)
2152 break;
2153 tmp = tmp->nexth;
2154 }
2155 if (tmp != NULL) {
2156 ret->nexth = tmp->nexth;
2157 tmp->nexth = ret;
2158 } else {
2159 ret->nexth = elemDef->attributes;
2160 elemDef->attributes = ret;
2161 }
2162 }
Owen Taylor3473f882001-02-23 17:55:21 +00002163 }
2164
2165 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002166 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00002167 */
2168 ret->parent = dtd;
Owen Taylor3473f882001-02-23 17:55:21 +00002169 if (dtd->last == NULL) {
2170 dtd->children = dtd->last = (xmlNodePtr) ret;
2171 } else {
2172 dtd->last->next = (xmlNodePtr) ret;
2173 ret->prev = dtd->last;
2174 dtd->last = (xmlNodePtr) ret;
2175 }
2176 return(ret);
2177}
2178
2179/**
2180 * xmlFreeAttributeTable:
2181 * @table: An attribute table
2182 *
2183 * Deallocate the memory used by an entities hash table.
2184 */
2185void
2186xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2187 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
2188}
2189
Daniel Veillard652327a2003-09-29 18:02:38 +00002190#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002191/**
2192 * xmlCopyAttribute:
2193 * @attr: An attribute
2194 *
2195 * Build a copy of an attribute.
2196 *
2197 * Returns the new xmlAttributePtr or NULL in case of error.
2198 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002199static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002200xmlCopyAttribute(xmlAttributePtr attr) {
2201 xmlAttributePtr cur;
2202
2203 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2204 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002205 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002206 return(NULL);
2207 }
2208 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00002209 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00002210 cur->atype = attr->atype;
2211 cur->def = attr->def;
2212 cur->tree = xmlCopyEnumeration(attr->tree);
2213 if (attr->elem != NULL)
2214 cur->elem = xmlStrdup(attr->elem);
2215 if (attr->name != NULL)
2216 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002217 if (attr->prefix != NULL)
2218 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002219 if (attr->defaultValue != NULL)
2220 cur->defaultValue = xmlStrdup(attr->defaultValue);
2221 return(cur);
2222}
2223
2224/**
2225 * xmlCopyAttributeTable:
2226 * @table: An attribute table
2227 *
2228 * Build a copy of an attribute table.
2229 *
2230 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2231 */
2232xmlAttributeTablePtr
2233xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2234 return((xmlAttributeTablePtr) xmlHashCopy(table,
2235 (xmlHashCopier) xmlCopyAttribute));
2236}
Daniel Veillard652327a2003-09-29 18:02:38 +00002237#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002238
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002239#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002240/**
2241 * xmlDumpAttributeDecl:
2242 * @buf: the XML buffer output
2243 * @attr: An attribute declaration
2244 *
2245 * This will dump the content of the attribute declaration as an XML
2246 * DTD definition
2247 */
2248void
2249xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002250 if ((buf == NULL) || (attr == NULL))
2251 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002252 xmlBufferWriteChar(buf, "<!ATTLIST ");
2253 xmlBufferWriteCHAR(buf, attr->elem);
2254 xmlBufferWriteChar(buf, " ");
2255 if (attr->prefix != NULL) {
2256 xmlBufferWriteCHAR(buf, attr->prefix);
2257 xmlBufferWriteChar(buf, ":");
2258 }
2259 xmlBufferWriteCHAR(buf, attr->name);
2260 switch (attr->atype) {
2261 case XML_ATTRIBUTE_CDATA:
2262 xmlBufferWriteChar(buf, " CDATA");
2263 break;
2264 case XML_ATTRIBUTE_ID:
2265 xmlBufferWriteChar(buf, " ID");
2266 break;
2267 case XML_ATTRIBUTE_IDREF:
2268 xmlBufferWriteChar(buf, " IDREF");
2269 break;
2270 case XML_ATTRIBUTE_IDREFS:
2271 xmlBufferWriteChar(buf, " IDREFS");
2272 break;
2273 case XML_ATTRIBUTE_ENTITY:
2274 xmlBufferWriteChar(buf, " ENTITY");
2275 break;
2276 case XML_ATTRIBUTE_ENTITIES:
2277 xmlBufferWriteChar(buf, " ENTITIES");
2278 break;
2279 case XML_ATTRIBUTE_NMTOKEN:
2280 xmlBufferWriteChar(buf, " NMTOKEN");
2281 break;
2282 case XML_ATTRIBUTE_NMTOKENS:
2283 xmlBufferWriteChar(buf, " NMTOKENS");
2284 break;
2285 case XML_ATTRIBUTE_ENUMERATION:
2286 xmlBufferWriteChar(buf, " (");
2287 xmlDumpEnumeration(buf, attr->tree);
2288 break;
2289 case XML_ATTRIBUTE_NOTATION:
2290 xmlBufferWriteChar(buf, " NOTATION (");
2291 xmlDumpEnumeration(buf, attr->tree);
2292 break;
2293 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002294 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2295 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2296 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002297 }
2298 switch (attr->def) {
2299 case XML_ATTRIBUTE_NONE:
2300 break;
2301 case XML_ATTRIBUTE_REQUIRED:
2302 xmlBufferWriteChar(buf, " #REQUIRED");
2303 break;
2304 case XML_ATTRIBUTE_IMPLIED:
2305 xmlBufferWriteChar(buf, " #IMPLIED");
2306 break;
2307 case XML_ATTRIBUTE_FIXED:
2308 xmlBufferWriteChar(buf, " #FIXED");
2309 break;
2310 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002311 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2312 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2313 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002314 }
2315 if (attr->defaultValue != NULL) {
2316 xmlBufferWriteChar(buf, " ");
2317 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2318 }
2319 xmlBufferWriteChar(buf, ">\n");
2320}
2321
2322/**
William M. Brack9e660592003-10-20 14:56:06 +00002323 * xmlDumpAttributeDeclScan:
2324 * @attr: An attribute declaration
2325 * @buf: the XML buffer output
2326 *
2327 * This is used with the hash scan function - just reverses arguments
2328 */
2329static void
2330xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2331 xmlDumpAttributeDecl(buf, attr);
2332}
2333
2334/**
Owen Taylor3473f882001-02-23 17:55:21 +00002335 * xmlDumpAttributeTable:
2336 * @buf: the XML buffer output
2337 * @table: An attribute table
2338 *
2339 * This will dump the content of the attribute table as an XML DTD definition
2340 */
2341void
2342xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002343 if ((buf == NULL) || (table == NULL))
2344 return;
William M. Brack9e660592003-10-20 14:56:06 +00002345 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002346}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002347#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002348
2349/************************************************************************
2350 * *
2351 * NOTATIONs *
2352 * *
2353 ************************************************************************/
2354/**
Owen Taylor3473f882001-02-23 17:55:21 +00002355 * xmlFreeNotation:
2356 * @not: A notation
2357 *
2358 * Deallocate the memory used by an notation definition
2359 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002360static void
Owen Taylor3473f882001-02-23 17:55:21 +00002361xmlFreeNotation(xmlNotationPtr nota) {
2362 if (nota == NULL) return;
2363 if (nota->name != NULL)
2364 xmlFree((xmlChar *) nota->name);
2365 if (nota->PublicID != NULL)
2366 xmlFree((xmlChar *) nota->PublicID);
2367 if (nota->SystemID != NULL)
2368 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002369 xmlFree(nota);
2370}
2371
2372
2373/**
2374 * xmlAddNotationDecl:
2375 * @dtd: pointer to the DTD
2376 * @ctxt: the validation context
2377 * @name: the entity name
2378 * @PublicID: the public identifier or NULL
2379 * @SystemID: the system identifier or NULL
2380 *
2381 * Register a new notation declaration
2382 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002383 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002384 */
2385xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002386xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002387 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002388 const xmlChar *PublicID, const xmlChar *SystemID) {
2389 xmlNotationPtr ret;
2390 xmlNotationTablePtr table;
2391
2392 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002393 return(NULL);
2394 }
2395 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002396 return(NULL);
2397 }
2398 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002399 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002400 }
2401
2402 /*
2403 * Create the Notation table if needed.
2404 */
2405 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002406 if (table == NULL) {
2407 xmlDictPtr dict = NULL;
2408 if (dtd->doc != NULL)
2409 dict = dtd->doc->dict;
2410
2411 dtd->notations = table = xmlHashCreateDict(0, dict);
2412 }
Owen Taylor3473f882001-02-23 17:55:21 +00002413 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002414 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002415 "xmlAddNotationDecl: Table creation failed!\n");
2416 return(NULL);
2417 }
2418
2419 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2420 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002421 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002422 return(NULL);
2423 }
2424 memset(ret, 0, sizeof(xmlNotation));
2425
2426 /*
2427 * fill the structure.
2428 */
2429 ret->name = xmlStrdup(name);
2430 if (SystemID != NULL)
2431 ret->SystemID = xmlStrdup(SystemID);
2432 if (PublicID != NULL)
2433 ret->PublicID = xmlStrdup(PublicID);
2434
2435 /*
2436 * Validity Check:
2437 * Check the DTD for previous declarations of the ATTLIST
2438 */
2439 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002440#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002441 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2442 "xmlAddNotationDecl: %s already defined\n",
2443 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002444#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002445 xmlFreeNotation(ret);
2446 return(NULL);
2447 }
2448 return(ret);
2449}
2450
2451/**
2452 * xmlFreeNotationTable:
2453 * @table: An notation table
2454 *
2455 * Deallocate the memory used by an entities hash table.
2456 */
2457void
2458xmlFreeNotationTable(xmlNotationTablePtr table) {
2459 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2460}
2461
Daniel Veillard652327a2003-09-29 18:02:38 +00002462#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002463/**
2464 * xmlCopyNotation:
2465 * @nota: A notation
2466 *
2467 * Build a copy of a notation.
2468 *
2469 * Returns the new xmlNotationPtr or NULL in case of error.
2470 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002471static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002472xmlCopyNotation(xmlNotationPtr nota) {
2473 xmlNotationPtr cur;
2474
2475 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2476 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002477 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002478 return(NULL);
2479 }
2480 if (nota->name != NULL)
2481 cur->name = xmlStrdup(nota->name);
2482 else
2483 cur->name = NULL;
2484 if (nota->PublicID != NULL)
2485 cur->PublicID = xmlStrdup(nota->PublicID);
2486 else
2487 cur->PublicID = NULL;
2488 if (nota->SystemID != NULL)
2489 cur->SystemID = xmlStrdup(nota->SystemID);
2490 else
2491 cur->SystemID = NULL;
2492 return(cur);
2493}
2494
2495/**
2496 * xmlCopyNotationTable:
2497 * @table: A notation table
2498 *
2499 * Build a copy of a notation table.
2500 *
2501 * Returns the new xmlNotationTablePtr or NULL in case of error.
2502 */
2503xmlNotationTablePtr
2504xmlCopyNotationTable(xmlNotationTablePtr table) {
2505 return((xmlNotationTablePtr) xmlHashCopy(table,
2506 (xmlHashCopier) xmlCopyNotation));
2507}
Daniel Veillard652327a2003-09-29 18:02:38 +00002508#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002509
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002510#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002511/**
2512 * xmlDumpNotationDecl:
2513 * @buf: the XML buffer output
2514 * @nota: A notation declaration
2515 *
2516 * This will dump the content the notation declaration as an XML DTD definition
2517 */
2518void
2519xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002520 if ((buf == NULL) || (nota == NULL))
2521 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002522 xmlBufferWriteChar(buf, "<!NOTATION ");
2523 xmlBufferWriteCHAR(buf, nota->name);
2524 if (nota->PublicID != NULL) {
2525 xmlBufferWriteChar(buf, " PUBLIC ");
2526 xmlBufferWriteQuotedString(buf, nota->PublicID);
2527 if (nota->SystemID != NULL) {
2528 xmlBufferWriteChar(buf, " ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002529 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002530 }
2531 } else {
2532 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002533 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002534 }
2535 xmlBufferWriteChar(buf, " >\n");
2536}
2537
2538/**
William M. Brack9e660592003-10-20 14:56:06 +00002539 * xmlDumpNotationDeclScan:
2540 * @nota: A notation declaration
2541 * @buf: the XML buffer output
2542 *
2543 * This is called with the hash scan function, and just reverses args
2544 */
2545static void
2546xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2547 xmlDumpNotationDecl(buf, nota);
2548}
2549
2550/**
Owen Taylor3473f882001-02-23 17:55:21 +00002551 * xmlDumpNotationTable:
2552 * @buf: the XML buffer output
2553 * @table: A notation table
2554 *
2555 * This will dump the content of the notation table as an XML DTD definition
2556 */
2557void
2558xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002559 if ((buf == NULL) || (table == NULL))
2560 return;
William M. Brack9e660592003-10-20 14:56:06 +00002561 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002562}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002563#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002564
2565/************************************************************************
2566 * *
2567 * IDs *
2568 * *
2569 ************************************************************************/
2570/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002571 * DICT_FREE:
2572 * @str: a string
2573 *
2574 * Free a string if it is not owned by the "dict" dictionnary in the
2575 * current scope
2576 */
2577#define DICT_FREE(str) \
2578 if ((str) && ((!dict) || \
2579 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2580 xmlFree((char *)(str));
2581
2582/**
Owen Taylor3473f882001-02-23 17:55:21 +00002583 * xmlFreeID:
2584 * @not: A id
2585 *
2586 * Deallocate the memory used by an id definition
2587 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002588static void
Owen Taylor3473f882001-02-23 17:55:21 +00002589xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002590 xmlDictPtr dict = NULL;
2591
Owen Taylor3473f882001-02-23 17:55:21 +00002592 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002593
2594 if (id->doc != NULL)
2595 dict = id->doc->dict;
2596
Owen Taylor3473f882001-02-23 17:55:21 +00002597 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002598 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002599 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002600 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002601 xmlFree(id);
2602}
2603
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002604
Owen Taylor3473f882001-02-23 17:55:21 +00002605/**
2606 * xmlAddID:
2607 * @ctxt: the validation context
2608 * @doc: pointer to the document
2609 * @value: the value name
2610 * @attr: the attribute holding the ID
2611 *
2612 * Register a new id declaration
2613 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002614 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002615 */
2616xmlIDPtr
2617xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2618 xmlAttrPtr attr) {
2619 xmlIDPtr ret;
2620 xmlIDTablePtr table;
2621
2622 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002623 return(NULL);
2624 }
2625 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002626 return(NULL);
2627 }
2628 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002629 return(NULL);
2630 }
2631
2632 /*
2633 * Create the ID table if needed.
2634 */
2635 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002636 if (table == NULL) {
2637 doc->ids = table = xmlHashCreateDict(0, doc->dict);
2638 }
Owen Taylor3473f882001-02-23 17:55:21 +00002639 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002640 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002641 "xmlAddID: Table creation failed!\n");
2642 return(NULL);
2643 }
2644
2645 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2646 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002647 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002648 return(NULL);
2649 }
2650
2651 /*
2652 * fill the structure.
2653 */
2654 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002655 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002656 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2657 /*
2658 * Operating in streaming mode, attr is gonna disapear
2659 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002660 if (doc->dict != NULL)
2661 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2662 else
2663 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002664 ret->attr = NULL;
2665 } else {
2666 ret->attr = attr;
2667 ret->name = NULL;
2668 }
2669 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002670
2671 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002672#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002673 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002674 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002675 */
Daniel Veillardd3669b22004-02-25 12:34:55 +00002676 if ((ctxt != NULL) && (ctxt->error != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002677 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2678 "ID %s already defined\n",
2679 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002680 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002681#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002682 xmlFreeID(ret);
2683 return(NULL);
2684 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002685 if (attr != NULL)
2686 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002687 return(ret);
2688}
2689
2690/**
2691 * xmlFreeIDTable:
2692 * @table: An id table
2693 *
2694 * Deallocate the memory used by an ID hash table.
2695 */
2696void
2697xmlFreeIDTable(xmlIDTablePtr table) {
2698 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2699}
2700
2701/**
2702 * xmlIsID:
2703 * @doc: the document
2704 * @elem: the element carrying the attribute
2705 * @attr: the attribute
2706 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002707 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002708 * then this is done if DTD loading has been requested. In the case
2709 * of HTML documents parsed with the HTML parser, then ID detection is
2710 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002711 *
2712 * Returns 0 or 1 depending on the lookup result
2713 */
2714int
2715xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00002716 if ((attr == NULL) || (attr->name == NULL)) return(0);
2717 if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2718 (!strcmp((char *) attr->name, "id")) &&
2719 (!strcmp((char *) attr->ns->prefix, "xml")))
2720 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002721 if (doc == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002722 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2723 return(0);
2724 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Rob Richards04bffc02006-03-03 16:44:37 +00002725 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2726 ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
Daniel Veillard38431c32007-06-12 16:20:09 +00002727 ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
Owen Taylor3473f882001-02-23 17:55:21 +00002728 return(1);
2729 return(0);
Daniel Veillard379a3b72005-08-12 10:18:14 +00002730 } else if (elem == NULL) {
2731 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002732 } else {
Daniel Veillard465a0002005-08-22 12:07:04 +00002733 xmlAttributePtr attrDecl = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002734
Daniel Veillard379a3b72005-08-12 10:18:14 +00002735 xmlChar felem[50], fattr[50];
2736 xmlChar *fullelemname, *fullattrname;
2737
2738 fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2739 xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2740 (xmlChar *)elem->name;
2741
2742 fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2743 xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2744 (xmlChar *)attr->name;
2745
2746 if (fullelemname != NULL && fullattrname != NULL) {
2747 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2748 fullattrname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002749 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillard379a3b72005-08-12 10:18:14 +00002750 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2751 fullattrname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002752 }
Owen Taylor3473f882001-02-23 17:55:21 +00002753
Daniel Veillard379a3b72005-08-12 10:18:14 +00002754 if ((fullattrname != fattr) && (fullattrname != attr->name))
2755 xmlFree(fullattrname);
2756 if ((fullelemname != felem) && (fullelemname != elem->name))
2757 xmlFree(fullelemname);
2758
Owen Taylor3473f882001-02-23 17:55:21 +00002759 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2760 return(1);
2761 }
2762 return(0);
2763}
2764
2765/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002766 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002767 * @doc: the document
2768 * @attr: the attribute
2769 *
2770 * Remove the given attribute from the ID table maintained internally.
2771 *
2772 * Returns -1 if the lookup failed and 0 otherwise
2773 */
2774int
2775xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002776 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002777 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002778 xmlChar *ID;
2779
2780 if (doc == NULL) return(-1);
2781 if (attr == NULL) return(-1);
2782 table = (xmlIDTablePtr) doc->ids;
2783 if (table == NULL)
2784 return(-1);
2785
2786 if (attr == NULL)
2787 return(-1);
2788 ID = xmlNodeListGetString(doc, attr->children, 1);
2789 if (ID == NULL)
2790 return(-1);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002791 id = xmlHashLookup(table, ID);
2792 if (id == NULL || id->attr != attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002793 xmlFree(ID);
2794 return(-1);
2795 }
Daniel Veillard91b955c2004-12-10 10:26:42 +00002796 xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID);
Owen Taylor3473f882001-02-23 17:55:21 +00002797 xmlFree(ID);
Daniel Veillardda6f4af2005-06-20 17:17:54 +00002798 attr->atype = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002799 return(0);
2800}
2801
2802/**
2803 * xmlGetID:
2804 * @doc: pointer to the document
2805 * @ID: the ID value
2806 *
2807 * Search the attribute declaring the given ID
2808 *
2809 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2810 */
2811xmlAttrPtr
2812xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2813 xmlIDTablePtr table;
2814 xmlIDPtr id;
2815
2816 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002817 return(NULL);
2818 }
2819
2820 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002821 return(NULL);
2822 }
2823
2824 table = (xmlIDTablePtr) doc->ids;
2825 if (table == NULL)
2826 return(NULL);
2827
2828 id = xmlHashLookup(table, ID);
2829 if (id == NULL)
2830 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002831 if (id->attr == NULL) {
2832 /*
2833 * We are operating on a stream, return a well known reference
2834 * since the attribute node doesn't exist anymore
2835 */
2836 return((xmlAttrPtr) doc);
2837 }
Owen Taylor3473f882001-02-23 17:55:21 +00002838 return(id->attr);
2839}
2840
2841/************************************************************************
2842 * *
2843 * Refs *
2844 * *
2845 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002846typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002847{
2848 xmlListPtr l;
2849 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002850} xmlRemoveMemo;
2851
2852typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2853
2854typedef struct xmlValidateMemo_t
2855{
2856 xmlValidCtxtPtr ctxt;
2857 const xmlChar *name;
2858} xmlValidateMemo;
2859
2860typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002861
2862/**
Owen Taylor3473f882001-02-23 17:55:21 +00002863 * xmlFreeRef:
2864 * @lk: A list link
2865 *
2866 * Deallocate the memory used by a ref definition
2867 */
2868static void
2869xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002870 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2871 if (ref == NULL) return;
2872 if (ref->value != NULL)
2873 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002874 if (ref->name != NULL)
2875 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002876 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002877}
2878
2879/**
2880 * xmlFreeRefList:
2881 * @list_ref: A list of references.
2882 *
2883 * Deallocate the memory used by a list of references
2884 */
2885static void
2886xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002887 if (list_ref == NULL) return;
2888 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002889}
2890
2891/**
2892 * xmlWalkRemoveRef:
2893 * @data: Contents of current link
2894 * @user: Value supplied by the user
2895 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002896 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002897 */
2898static int
2899xmlWalkRemoveRef(const void *data, const void *user)
2900{
Daniel Veillard37721922001-05-04 15:21:12 +00002901 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2902 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2903 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002904
Daniel Veillard37721922001-05-04 15:21:12 +00002905 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2906 xmlListRemoveFirst(ref_list, (void *)data);
2907 return 0;
2908 }
2909 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002910}
2911
2912/**
Daniel Veillard770075b2004-02-25 10:44:30 +00002913 * xmlDummyCompare
2914 * @data0: Value supplied by the user
2915 * @data1: Value supplied by the user
2916 *
2917 * Do nothing, return 0. Used to create unordered lists.
2918 */
2919static int
Daniel Veillardf54cd532004-02-25 11:52:31 +00002920xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2921 const void *data1 ATTRIBUTE_UNUSED)
Daniel Veillard770075b2004-02-25 10:44:30 +00002922{
2923 return (0);
2924}
2925
2926/**
Owen Taylor3473f882001-02-23 17:55:21 +00002927 * xmlAddRef:
2928 * @ctxt: the validation context
2929 * @doc: pointer to the document
2930 * @value: the value name
2931 * @attr: the attribute holding the Ref
2932 *
2933 * Register a new ref declaration
2934 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002935 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002936 */
2937xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002938xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002939 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002940 xmlRefPtr ret;
2941 xmlRefTablePtr table;
2942 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002943
Daniel Veillard37721922001-05-04 15:21:12 +00002944 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002945 return(NULL);
2946 }
2947 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002948 return(NULL);
2949 }
2950 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002951 return(NULL);
2952 }
Owen Taylor3473f882001-02-23 17:55:21 +00002953
Daniel Veillard37721922001-05-04 15:21:12 +00002954 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002955 * Create the Ref table if needed.
2956 */
Daniel Veillard37721922001-05-04 15:21:12 +00002957 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002958 if (table == NULL) {
2959 doc->refs = table = xmlHashCreateDict(0, doc->dict);
2960 }
Daniel Veillard37721922001-05-04 15:21:12 +00002961 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002962 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002963 "xmlAddRef: Table creation failed!\n");
2964 return(NULL);
2965 }
Owen Taylor3473f882001-02-23 17:55:21 +00002966
Daniel Veillard37721922001-05-04 15:21:12 +00002967 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2968 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002969 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002970 return(NULL);
2971 }
Owen Taylor3473f882001-02-23 17:55:21 +00002972
Daniel Veillard37721922001-05-04 15:21:12 +00002973 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002974 * fill the structure.
2975 */
Daniel Veillard37721922001-05-04 15:21:12 +00002976 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002977 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2978 /*
2979 * Operating in streaming mode, attr is gonna disapear
2980 */
2981 ret->name = xmlStrdup(attr->name);
2982 ret->attr = NULL;
2983 } else {
2984 ret->name = NULL;
2985 ret->attr = attr;
2986 }
2987 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002988
Daniel Veillard37721922001-05-04 15:21:12 +00002989 /* To add a reference :-
2990 * References are maintained as a list of references,
2991 * Lookup the entry, if no entry create new nodelist
2992 * Add the owning node to the NodeList
2993 * Return the ref
2994 */
Owen Taylor3473f882001-02-23 17:55:21 +00002995
Daniel Veillard37721922001-05-04 15:21:12 +00002996 if (NULL == (ref_list = xmlHashLookup(table, value))) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002997 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002998 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2999 "xmlAddRef: Reference list creation failed!\n",
3000 NULL);
Daniel Veillardf6cf57a2007-05-09 23:53:30 +00003001 goto failed;
Daniel Veillard37721922001-05-04 15:21:12 +00003002 }
3003 if (xmlHashAddEntry(table, value, ref_list) < 0) {
3004 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00003005 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3006 "xmlAddRef: Reference list insertion failed!\n",
3007 NULL);
Daniel Veillardf6cf57a2007-05-09 23:53:30 +00003008 goto failed;
Daniel Veillard37721922001-05-04 15:21:12 +00003009 }
3010 }
Daniel Veillardf6cf57a2007-05-09 23:53:30 +00003011 if (xmlListAppend(ref_list, ret) != 0) {
3012 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3013 "xmlAddRef: Reference list insertion failed!\n",
3014 NULL);
3015 goto failed;
3016 }
Daniel Veillard37721922001-05-04 15:21:12 +00003017 return(ret);
Daniel Veillardf6cf57a2007-05-09 23:53:30 +00003018failed:
3019 if (ret != NULL) {
3020 if (ret->value != NULL)
3021 xmlFree((char *)ret->value);
3022 if (ret->name != NULL)
3023 xmlFree((char *)ret->name);
3024 xmlFree(ret);
3025 }
3026 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003027}
3028
3029/**
3030 * xmlFreeRefTable:
3031 * @table: An ref table
3032 *
3033 * Deallocate the memory used by an Ref hash table.
3034 */
3035void
3036xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00003037 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00003038}
3039
3040/**
3041 * xmlIsRef:
3042 * @doc: the document
3043 * @elem: the element carrying the attribute
3044 * @attr: the attribute
3045 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003046 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00003047 * then this is simple, otherwise we use an heuristic: name Ref (upper
3048 * or lowercase).
3049 *
3050 * Returns 0 or 1 depending on the lookup result
3051 */
3052int
3053xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003054 if (attr == NULL)
3055 return(0);
3056 if (doc == NULL) {
3057 doc = attr->doc;
3058 if (doc == NULL) return(0);
3059 }
3060
Daniel Veillard37721922001-05-04 15:21:12 +00003061 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3062 return(0);
3063 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3064 /* TODO @@@ */
3065 return(0);
3066 } else {
3067 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00003068
Daniel Veillardce244ad2004-11-05 10:03:46 +00003069 if (elem == NULL) return(0);
Daniel Veillard37721922001-05-04 15:21:12 +00003070 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3071 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3072 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3073 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00003074
Daniel Veillard37721922001-05-04 15:21:12 +00003075 if ((attrDecl != NULL) &&
3076 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3077 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3078 return(1);
3079 }
3080 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003081}
3082
3083/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003084 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00003085 * @doc: the document
3086 * @attr: the attribute
3087 *
3088 * Remove the given attribute from the Ref table maintained internally.
3089 *
3090 * Returns -1 if the lookup failed and 0 otherwise
3091 */
3092int
3093xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00003094 xmlListPtr ref_list;
3095 xmlRefTablePtr table;
3096 xmlChar *ID;
3097 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00003098
Daniel Veillard37721922001-05-04 15:21:12 +00003099 if (doc == NULL) return(-1);
3100 if (attr == NULL) return(-1);
3101 table = (xmlRefTablePtr) doc->refs;
3102 if (table == NULL)
3103 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003104
Daniel Veillard37721922001-05-04 15:21:12 +00003105 if (attr == NULL)
3106 return(-1);
3107 ID = xmlNodeListGetString(doc, attr->children, 1);
3108 if (ID == NULL)
3109 return(-1);
3110 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00003111
Daniel Veillard37721922001-05-04 15:21:12 +00003112 if(ref_list == NULL) {
3113 xmlFree(ID);
3114 return (-1);
3115 }
3116 /* At this point, ref_list refers to a list of references which
3117 * have the same key as the supplied attr. Our list of references
3118 * is ordered by reference address and we don't have that information
3119 * here to use when removing. We'll have to walk the list and
3120 * check for a matching attribute, when we find one stop the walk
3121 * and remove the entry.
3122 * The list is ordered by reference, so that means we don't have the
3123 * key. Passing the list and the reference to the walker means we
3124 * will have enough data to be able to remove the entry.
3125 */
3126 target.l = ref_list;
3127 target.ap = attr;
3128
3129 /* Remove the supplied attr from our list */
3130 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00003131
Daniel Veillard37721922001-05-04 15:21:12 +00003132 /*If the list is empty then remove the list entry in the hash */
3133 if (xmlListEmpty(ref_list))
3134 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
3135 xmlFreeRefList);
3136 xmlFree(ID);
3137 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003138}
3139
3140/**
3141 * xmlGetRefs:
3142 * @doc: pointer to the document
3143 * @ID: the ID value
3144 *
3145 * Find the set of references for the supplied ID.
3146 *
3147 * Returns NULL if not found, otherwise node set for the ID.
3148 */
3149xmlListPtr
3150xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00003151 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00003152
Daniel Veillard37721922001-05-04 15:21:12 +00003153 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003154 return(NULL);
3155 }
Owen Taylor3473f882001-02-23 17:55:21 +00003156
Daniel Veillard37721922001-05-04 15:21:12 +00003157 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003158 return(NULL);
3159 }
Owen Taylor3473f882001-02-23 17:55:21 +00003160
Daniel Veillard37721922001-05-04 15:21:12 +00003161 table = (xmlRefTablePtr) doc->refs;
3162 if (table == NULL)
3163 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003164
Daniel Veillard37721922001-05-04 15:21:12 +00003165 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00003166}
3167
3168/************************************************************************
3169 * *
3170 * Routines for validity checking *
3171 * *
3172 ************************************************************************/
3173
3174/**
3175 * xmlGetDtdElementDesc:
3176 * @dtd: a pointer to the DtD to search
3177 * @name: the element name
3178 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003179 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003180 *
3181 * returns the xmlElementPtr if found or NULL
3182 */
3183
3184xmlElementPtr
3185xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3186 xmlElementTablePtr table;
3187 xmlElementPtr cur;
3188 xmlChar *uqname = NULL, *prefix = NULL;
3189
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00003190 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003191 if (dtd->elements == NULL)
3192 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003193 table = (xmlElementTablePtr) dtd->elements;
3194
3195 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003196 if (uqname != NULL)
3197 name = uqname;
3198 cur = xmlHashLookup2(table, name, prefix);
3199 if (prefix != NULL) xmlFree(prefix);
3200 if (uqname != NULL) xmlFree(uqname);
3201 return(cur);
3202}
3203/**
3204 * xmlGetDtdElementDesc2:
3205 * @dtd: a pointer to the DtD to search
3206 * @name: the element name
3207 * @create: create an empty description if not found
3208 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003209 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00003210 *
3211 * returns the xmlElementPtr if found or NULL
3212 */
3213
Daniel Veillard86fd5a72001-12-13 14:55:21 +00003214static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00003215xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3216 xmlElementTablePtr table;
3217 xmlElementPtr cur;
3218 xmlChar *uqname = NULL, *prefix = NULL;
3219
3220 if (dtd == NULL) return(NULL);
3221 if (dtd->elements == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003222 xmlDictPtr dict = NULL;
3223
3224 if (dtd->doc != NULL)
3225 dict = dtd->doc->dict;
3226
Daniel Veillarda10efa82001-04-18 13:09:01 +00003227 if (!create)
3228 return(NULL);
3229 /*
3230 * Create the Element table if needed.
3231 */
3232 table = (xmlElementTablePtr) dtd->elements;
3233 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003234 table = xmlHashCreateDict(0, dict);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003235 dtd->elements = (void *) table;
3236 }
3237 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003238 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003239 return(NULL);
3240 }
3241 }
3242 table = (xmlElementTablePtr) dtd->elements;
3243
3244 uqname = xmlSplitQName2(name, &prefix);
3245 if (uqname != NULL)
3246 name = uqname;
3247 cur = xmlHashLookup2(table, name, prefix);
3248 if ((cur == NULL) && (create)) {
3249 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3250 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003251 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003252 return(NULL);
3253 }
3254 memset(cur, 0, sizeof(xmlElement));
3255 cur->type = XML_ELEMENT_DECL;
3256
3257 /*
3258 * fill the structure.
3259 */
3260 cur->name = xmlStrdup(name);
3261 cur->prefix = xmlStrdup(prefix);
3262 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3263
3264 xmlHashAddEntry2(table, name, prefix, cur);
3265 }
3266 if (prefix != NULL) xmlFree(prefix);
3267 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003268 return(cur);
3269}
3270
3271/**
3272 * xmlGetDtdQElementDesc:
3273 * @dtd: a pointer to the DtD to search
3274 * @name: the element name
3275 * @prefix: the element namespace prefix
3276 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003277 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003278 *
3279 * returns the xmlElementPtr if found or NULL
3280 */
3281
Daniel Veillard48da9102001-08-07 01:10:10 +00003282xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003283xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3284 const xmlChar *prefix) {
3285 xmlElementTablePtr table;
3286
3287 if (dtd == NULL) return(NULL);
3288 if (dtd->elements == NULL) return(NULL);
3289 table = (xmlElementTablePtr) dtd->elements;
3290
3291 return(xmlHashLookup2(table, name, prefix));
3292}
3293
3294/**
3295 * xmlGetDtdAttrDesc:
3296 * @dtd: a pointer to the DtD to search
3297 * @elem: the element name
3298 * @name: the attribute name
3299 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003300 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003301 * this element.
3302 *
3303 * returns the xmlAttributePtr if found or NULL
3304 */
3305
3306xmlAttributePtr
3307xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3308 xmlAttributeTablePtr table;
3309 xmlAttributePtr cur;
3310 xmlChar *uqname = NULL, *prefix = NULL;
3311
3312 if (dtd == NULL) return(NULL);
3313 if (dtd->attributes == NULL) return(NULL);
3314
3315 table = (xmlAttributeTablePtr) dtd->attributes;
3316 if (table == NULL)
3317 return(NULL);
3318
3319 uqname = xmlSplitQName2(name, &prefix);
3320
3321 if (uqname != NULL) {
3322 cur = xmlHashLookup3(table, uqname, prefix, elem);
3323 if (prefix != NULL) xmlFree(prefix);
3324 if (uqname != NULL) xmlFree(uqname);
3325 } else
3326 cur = xmlHashLookup3(table, name, NULL, elem);
3327 return(cur);
3328}
3329
3330/**
3331 * xmlGetDtdQAttrDesc:
3332 * @dtd: a pointer to the DtD to search
3333 * @elem: the element name
3334 * @name: the attribute name
3335 * @prefix: the attribute namespace prefix
3336 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003337 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003338 * this element.
3339 *
3340 * returns the xmlAttributePtr if found or NULL
3341 */
3342
Daniel Veillard48da9102001-08-07 01:10:10 +00003343xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003344xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3345 const xmlChar *prefix) {
3346 xmlAttributeTablePtr table;
3347
3348 if (dtd == NULL) return(NULL);
3349 if (dtd->attributes == NULL) return(NULL);
3350 table = (xmlAttributeTablePtr) dtd->attributes;
3351
3352 return(xmlHashLookup3(table, name, prefix, elem));
3353}
3354
3355/**
3356 * xmlGetDtdNotationDesc:
3357 * @dtd: a pointer to the DtD to search
3358 * @name: the notation name
3359 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003360 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003361 *
3362 * returns the xmlNotationPtr if found or NULL
3363 */
3364
3365xmlNotationPtr
3366xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3367 xmlNotationTablePtr table;
3368
3369 if (dtd == NULL) return(NULL);
3370 if (dtd->notations == NULL) return(NULL);
3371 table = (xmlNotationTablePtr) dtd->notations;
3372
3373 return(xmlHashLookup(table, name));
3374}
3375
Daniel Veillardf54cd532004-02-25 11:52:31 +00003376#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003377/**
3378 * xmlValidateNotationUse:
3379 * @ctxt: the validation context
3380 * @doc: the document
3381 * @notationName: the notation name to check
3382 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003383 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003384 * - [ VC: Notation Declared ]
3385 *
3386 * returns 1 if valid or 0 otherwise
3387 */
3388
3389int
3390xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3391 const xmlChar *notationName) {
3392 xmlNotationPtr notaDecl;
3393 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3394
3395 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3396 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3397 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3398
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003399 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003400 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3401 "NOTATION %s is not declared\n",
3402 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003403 return(0);
3404 }
3405 return(1);
3406}
Daniel Veillardf54cd532004-02-25 11:52:31 +00003407#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003408
3409/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003410 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003411 * @doc: the document
3412 * @name: the element name
3413 *
3414 * Search in the DtDs whether an element accept Mixed content (or ANY)
3415 * basically if it is supposed to accept text childs
3416 *
3417 * returns 0 if no, 1 if yes, and -1 if no element description is available
3418 */
3419
3420int
3421xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3422 xmlElementPtr elemDecl;
3423
3424 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3425
3426 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3427 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3428 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3429 if (elemDecl == NULL) return(-1);
3430 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003431 case XML_ELEMENT_TYPE_UNDEFINED:
3432 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003433 case XML_ELEMENT_TYPE_ELEMENT:
3434 return(0);
3435 case XML_ELEMENT_TYPE_EMPTY:
3436 /*
3437 * return 1 for EMPTY since we want VC error to pop up
3438 * on <empty> </empty> for example
3439 */
3440 case XML_ELEMENT_TYPE_ANY:
3441 case XML_ELEMENT_TYPE_MIXED:
3442 return(1);
3443 }
3444 return(1);
3445}
3446
Daniel Veillard4432df22003-09-28 18:58:27 +00003447#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003448/**
3449 * xmlValidateNameValue:
3450 * @value: an Name value
3451 *
3452 * Validate that the given value match Name production
3453 *
3454 * returns 1 if valid or 0 otherwise
3455 */
3456
Daniel Veillard9b731d72002-04-14 12:56:08 +00003457int
Owen Taylor3473f882001-02-23 17:55:21 +00003458xmlValidateNameValue(const xmlChar *value) {
3459 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003460 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003461
3462 if (value == NULL) return(0);
3463 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003464 val = xmlStringCurrentChar(NULL, cur, &len);
3465 cur += len;
3466 if (!IS_LETTER(val) && (val != '_') &&
3467 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003468 return(0);
3469 }
3470
Daniel Veillardd8224e02002-01-13 15:43:22 +00003471 val = xmlStringCurrentChar(NULL, cur, &len);
3472 cur += len;
3473 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3474 (val == '.') || (val == '-') ||
3475 (val == '_') || (val == ':') ||
3476 (IS_COMBINING(val)) ||
3477 (IS_EXTENDER(val))) {
3478 val = xmlStringCurrentChar(NULL, cur, &len);
3479 cur += len;
3480 }
Owen Taylor3473f882001-02-23 17:55:21 +00003481
Daniel Veillardd8224e02002-01-13 15:43:22 +00003482 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003483
3484 return(1);
3485}
3486
3487/**
3488 * xmlValidateNamesValue:
3489 * @value: an Names value
3490 *
3491 * Validate that the given value match Names production
3492 *
3493 * returns 1 if valid or 0 otherwise
3494 */
3495
Daniel Veillard9b731d72002-04-14 12:56:08 +00003496int
Owen Taylor3473f882001-02-23 17:55:21 +00003497xmlValidateNamesValue(const xmlChar *value) {
3498 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003499 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003500
3501 if (value == NULL) return(0);
3502 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003503 val = xmlStringCurrentChar(NULL, cur, &len);
3504 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003505
Daniel Veillardd8224e02002-01-13 15:43:22 +00003506 if (!IS_LETTER(val) && (val != '_') &&
3507 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003508 return(0);
3509 }
3510
Daniel Veillardd8224e02002-01-13 15:43:22 +00003511 val = xmlStringCurrentChar(NULL, cur, &len);
3512 cur += len;
3513 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3514 (val == '.') || (val == '-') ||
3515 (val == '_') || (val == ':') ||
3516 (IS_COMBINING(val)) ||
3517 (IS_EXTENDER(val))) {
3518 val = xmlStringCurrentChar(NULL, cur, &len);
3519 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003520 }
3521
Daniel Veillard807b4de2004-09-26 14:42:56 +00003522 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3523 while (val == 0x20) {
3524 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003525 val = xmlStringCurrentChar(NULL, cur, &len);
3526 cur += len;
3527 }
3528
3529 if (!IS_LETTER(val) && (val != '_') &&
3530 (val != ':')) {
3531 return(0);
3532 }
3533 val = xmlStringCurrentChar(NULL, cur, &len);
3534 cur += len;
3535
3536 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3537 (val == '.') || (val == '-') ||
3538 (val == '_') || (val == ':') ||
3539 (IS_COMBINING(val)) ||
3540 (IS_EXTENDER(val))) {
3541 val = xmlStringCurrentChar(NULL, cur, &len);
3542 cur += len;
3543 }
3544 }
3545
3546 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003547
3548 return(1);
3549}
3550
3551/**
3552 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003553 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003554 *
3555 * Validate that the given value match Nmtoken production
3556 *
3557 * [ VC: Name Token ]
3558 *
3559 * returns 1 if valid or 0 otherwise
3560 */
3561
Daniel Veillard9b731d72002-04-14 12:56:08 +00003562int
Owen Taylor3473f882001-02-23 17:55:21 +00003563xmlValidateNmtokenValue(const xmlChar *value) {
3564 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003565 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003566
3567 if (value == NULL) return(0);
3568 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003569 val = xmlStringCurrentChar(NULL, cur, &len);
3570 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003571
Daniel Veillardd8224e02002-01-13 15:43:22 +00003572 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3573 (val != '.') && (val != '-') &&
3574 (val != '_') && (val != ':') &&
3575 (!IS_COMBINING(val)) &&
3576 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003577 return(0);
3578
Daniel Veillardd8224e02002-01-13 15:43:22 +00003579 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3580 (val == '.') || (val == '-') ||
3581 (val == '_') || (val == ':') ||
3582 (IS_COMBINING(val)) ||
3583 (IS_EXTENDER(val))) {
3584 val = xmlStringCurrentChar(NULL, cur, &len);
3585 cur += len;
3586 }
Owen Taylor3473f882001-02-23 17:55:21 +00003587
Daniel Veillardd8224e02002-01-13 15:43:22 +00003588 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003589
3590 return(1);
3591}
3592
3593/**
3594 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003595 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003596 *
3597 * Validate that the given value match Nmtokens production
3598 *
3599 * [ VC: Name Token ]
3600 *
3601 * returns 1 if valid or 0 otherwise
3602 */
3603
Daniel Veillard9b731d72002-04-14 12:56:08 +00003604int
Owen Taylor3473f882001-02-23 17:55:21 +00003605xmlValidateNmtokensValue(const xmlChar *value) {
3606 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003607 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003608
3609 if (value == NULL) return(0);
3610 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003611 val = xmlStringCurrentChar(NULL, cur, &len);
3612 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003613
Daniel Veillardd8224e02002-01-13 15:43:22 +00003614 while (IS_BLANK(val)) {
3615 val = xmlStringCurrentChar(NULL, cur, &len);
3616 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003617 }
3618
Daniel Veillardd8224e02002-01-13 15:43:22 +00003619 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3620 (val != '.') && (val != '-') &&
3621 (val != '_') && (val != ':') &&
3622 (!IS_COMBINING(val)) &&
3623 (!IS_EXTENDER(val)))
3624 return(0);
3625
3626 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3627 (val == '.') || (val == '-') ||
3628 (val == '_') || (val == ':') ||
3629 (IS_COMBINING(val)) ||
3630 (IS_EXTENDER(val))) {
3631 val = xmlStringCurrentChar(NULL, cur, &len);
3632 cur += len;
3633 }
3634
Daniel Veillard807b4de2004-09-26 14:42:56 +00003635 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3636 while (val == 0x20) {
3637 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003638 val = xmlStringCurrentChar(NULL, cur, &len);
3639 cur += len;
3640 }
3641 if (val == 0) return(1);
3642
3643 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3644 (val != '.') && (val != '-') &&
3645 (val != '_') && (val != ':') &&
3646 (!IS_COMBINING(val)) &&
3647 (!IS_EXTENDER(val)))
3648 return(0);
3649
3650 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3651 (val == '.') || (val == '-') ||
3652 (val == '_') || (val == ':') ||
3653 (IS_COMBINING(val)) ||
3654 (IS_EXTENDER(val))) {
3655 val = xmlStringCurrentChar(NULL, cur, &len);
3656 cur += len;
3657 }
3658 }
3659
3660 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003661
3662 return(1);
3663}
3664
3665/**
3666 * xmlValidateNotationDecl:
3667 * @ctxt: the validation context
3668 * @doc: a document instance
3669 * @nota: a notation definition
3670 *
3671 * Try to validate a single notation definition
3672 * basically it does the following checks as described by the
3673 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003674 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003675 * But this function get called anyway ...
3676 *
3677 * returns 1 if valid or 0 otherwise
3678 */
3679
3680int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003681xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3682 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003683 int ret = 1;
3684
3685 return(ret);
3686}
3687
3688/**
3689 * xmlValidateAttributeValue:
3690 * @type: an attribute type
3691 * @value: an attribute value
3692 *
3693 * Validate that the given attribute value match the proper production
3694 *
3695 * [ VC: ID ]
3696 * Values of type ID must match the Name production....
3697 *
3698 * [ VC: IDREF ]
3699 * Values of type IDREF must match the Name production, and values
3700 * of type IDREFS must match Names ...
3701 *
3702 * [ VC: Entity Name ]
3703 * Values of type ENTITY must match the Name production, values
3704 * of type ENTITIES must match Names ...
3705 *
3706 * [ VC: Name Token ]
3707 * Values of type NMTOKEN must match the Nmtoken production; values
3708 * of type NMTOKENS must match Nmtokens.
3709 *
3710 * returns 1 if valid or 0 otherwise
3711 */
3712
3713int
3714xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3715 switch (type) {
3716 case XML_ATTRIBUTE_ENTITIES:
3717 case XML_ATTRIBUTE_IDREFS:
3718 return(xmlValidateNamesValue(value));
3719 case XML_ATTRIBUTE_ENTITY:
3720 case XML_ATTRIBUTE_IDREF:
3721 case XML_ATTRIBUTE_ID:
3722 case XML_ATTRIBUTE_NOTATION:
3723 return(xmlValidateNameValue(value));
3724 case XML_ATTRIBUTE_NMTOKENS:
3725 case XML_ATTRIBUTE_ENUMERATION:
3726 return(xmlValidateNmtokensValue(value));
3727 case XML_ATTRIBUTE_NMTOKEN:
3728 return(xmlValidateNmtokenValue(value));
3729 case XML_ATTRIBUTE_CDATA:
3730 break;
3731 }
3732 return(1);
3733}
3734
3735/**
3736 * xmlValidateAttributeValue2:
3737 * @ctxt: the validation context
3738 * @doc: the document
3739 * @name: the attribute name (used for error reporting only)
3740 * @type: the attribute type
3741 * @value: the attribute value
3742 *
3743 * Validate that the given attribute value match a given type.
3744 * This typically cannot be done before having finished parsing
3745 * the subsets.
3746 *
3747 * [ VC: IDREF ]
3748 * Values of type IDREF must match one of the declared IDs
3749 * Values of type IDREFS must match a sequence of the declared IDs
3750 * each Name must match the value of an ID attribute on some element
3751 * in the XML document; i.e. IDREF values must match the value of
3752 * some ID attribute
3753 *
3754 * [ VC: Entity Name ]
3755 * Values of type ENTITY must match one declared entity
3756 * Values of type ENTITIES must match a sequence of declared entities
3757 *
3758 * [ VC: Notation Attributes ]
3759 * all notation names in the declaration must be declared.
3760 *
3761 * returns 1 if valid or 0 otherwise
3762 */
3763
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003764static int
Owen Taylor3473f882001-02-23 17:55:21 +00003765xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3766 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3767 int ret = 1;
3768 switch (type) {
3769 case XML_ATTRIBUTE_IDREFS:
3770 case XML_ATTRIBUTE_IDREF:
3771 case XML_ATTRIBUTE_ID:
3772 case XML_ATTRIBUTE_NMTOKENS:
3773 case XML_ATTRIBUTE_ENUMERATION:
3774 case XML_ATTRIBUTE_NMTOKEN:
3775 case XML_ATTRIBUTE_CDATA:
3776 break;
3777 case XML_ATTRIBUTE_ENTITY: {
3778 xmlEntityPtr ent;
3779
3780 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003781 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003782 if ((ent == NULL) && (doc->standalone == 1)) {
3783 doc->standalone = 0;
3784 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003785 }
Owen Taylor3473f882001-02-23 17:55:21 +00003786 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003787 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3788 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003789 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003790 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003791 ret = 0;
3792 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003793 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3794 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003795 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003796 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003797 ret = 0;
3798 }
3799 break;
3800 }
3801 case XML_ATTRIBUTE_ENTITIES: {
3802 xmlChar *dup, *nam = NULL, *cur, save;
3803 xmlEntityPtr ent;
3804
3805 dup = xmlStrdup(value);
3806 if (dup == NULL)
3807 return(0);
3808 cur = dup;
3809 while (*cur != 0) {
3810 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003811 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003812 save = *cur;
3813 *cur = 0;
3814 ent = xmlGetDocEntity(doc, nam);
3815 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003816 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3817 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003818 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003819 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003820 ret = 0;
3821 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003822 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3823 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003824 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003825 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003826 ret = 0;
3827 }
3828 if (save == 0)
3829 break;
3830 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003831 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003832 }
3833 xmlFree(dup);
3834 break;
3835 }
3836 case XML_ATTRIBUTE_NOTATION: {
3837 xmlNotationPtr nota;
3838
3839 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3840 if ((nota == NULL) && (doc->extSubset != NULL))
3841 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3842
3843 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003844 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3845 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003846 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003847 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003848 ret = 0;
3849 }
3850 break;
3851 }
3852 }
3853 return(ret);
3854}
3855
3856/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003857 * xmlValidCtxtNormalizeAttributeValue:
3858 * @ctxt: the validation context
3859 * @doc: the document
3860 * @elem: the parent
3861 * @name: the attribute name
3862 * @value: the attribute value
3863 * @ctxt: the validation context or NULL
3864 *
3865 * Does the validation related extra step of the normalization of attribute
3866 * values:
3867 *
3868 * If the declared value is not CDATA, then the XML processor must further
3869 * process the normalized attribute value by discarding any leading and
3870 * trailing space (#x20) characters, and by replacing sequences of space
3871 * (#x20) characters by single space (#x20) character.
3872 *
3873 * Also check VC: Standalone Document Declaration in P32, and update
3874 * ctxt->valid accordingly
3875 *
3876 * returns a new normalized string if normalization is needed, NULL otherwise
3877 * the caller must free the returned value.
3878 */
3879
3880xmlChar *
3881xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3882 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3883 xmlChar *ret, *dst;
3884 const xmlChar *src;
3885 xmlAttributePtr attrDecl = NULL;
3886 int extsubset = 0;
3887
3888 if (doc == NULL) return(NULL);
3889 if (elem == NULL) return(NULL);
3890 if (name == NULL) return(NULL);
3891 if (value == NULL) return(NULL);
3892
3893 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003894 xmlChar fn[50];
3895 xmlChar *fullname;
3896
3897 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3898 if (fullname == NULL)
Daniel Veillard24505b02005-07-28 23:49:35 +00003899 return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00003900 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003901 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003902 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003903 if (attrDecl != NULL)
3904 extsubset = 1;
3905 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003906 if ((fullname != fn) && (fullname != elem->name))
3907 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003908 }
3909 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3910 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3911 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3912 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3913 if (attrDecl != NULL)
3914 extsubset = 1;
3915 }
3916
3917 if (attrDecl == NULL)
3918 return(NULL);
3919 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3920 return(NULL);
3921
3922 ret = xmlStrdup(value);
3923 if (ret == NULL)
3924 return(NULL);
3925 src = value;
3926 dst = ret;
3927 while (*src == 0x20) src++;
3928 while (*src != 0) {
3929 if (*src == 0x20) {
3930 while (*src == 0x20) src++;
3931 if (*src != 0)
3932 *dst++ = 0x20;
3933 } else {
3934 *dst++ = *src++;
3935 }
3936 }
3937 *dst = 0;
3938 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003939 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003940"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003941 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003942 ctxt->valid = 0;
3943 }
3944 return(ret);
3945}
3946
3947/**
Owen Taylor3473f882001-02-23 17:55:21 +00003948 * xmlValidNormalizeAttributeValue:
3949 * @doc: the document
3950 * @elem: the parent
3951 * @name: the attribute name
3952 * @value: the attribute value
3953 *
3954 * Does the validation related extra step of the normalization of attribute
3955 * values:
3956 *
3957 * If the declared value is not CDATA, then the XML processor must further
3958 * process the normalized attribute value by discarding any leading and
3959 * trailing space (#x20) characters, and by replacing sequences of space
3960 * (#x20) characters by single space (#x20) character.
3961 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003962 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003963 * the caller must free the returned value.
3964 */
3965
3966xmlChar *
3967xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3968 const xmlChar *name, const xmlChar *value) {
3969 xmlChar *ret, *dst;
3970 const xmlChar *src;
3971 xmlAttributePtr attrDecl = NULL;
3972
3973 if (doc == NULL) return(NULL);
3974 if (elem == NULL) return(NULL);
3975 if (name == NULL) return(NULL);
3976 if (value == NULL) return(NULL);
3977
3978 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003979 xmlChar fn[50];
3980 xmlChar *fullname;
3981
3982 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3983 if (fullname == NULL)
Daniel Veillard24505b02005-07-28 23:49:35 +00003984 return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00003985 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003986 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003987 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3988 if ((fullname != fn) && (fullname != elem->name))
3989 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003990 }
3991 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3992 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3993 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3994
3995 if (attrDecl == NULL)
3996 return(NULL);
3997 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3998 return(NULL);
3999
4000 ret = xmlStrdup(value);
4001 if (ret == NULL)
4002 return(NULL);
4003 src = value;
4004 dst = ret;
4005 while (*src == 0x20) src++;
4006 while (*src != 0) {
4007 if (*src == 0x20) {
4008 while (*src == 0x20) src++;
4009 if (*src != 0)
4010 *dst++ = 0x20;
4011 } else {
4012 *dst++ = *src++;
4013 }
4014 }
4015 *dst = 0;
4016 return(ret);
4017}
4018
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004019static void
Owen Taylor3473f882001-02-23 17:55:21 +00004020xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00004021 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00004022 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4023}
4024
4025/**
4026 * xmlValidateAttributeDecl:
4027 * @ctxt: the validation context
4028 * @doc: a document instance
4029 * @attr: an attribute definition
4030 *
4031 * Try to validate a single attribute definition
4032 * basically it does the following checks as described by the
4033 * XML-1.0 recommendation:
4034 * - [ VC: Attribute Default Legal ]
4035 * - [ VC: Enumeration ]
4036 * - [ VC: ID Attribute Default ]
4037 *
4038 * The ID/IDREF uniqueness and matching are done separately
4039 *
4040 * returns 1 if valid or 0 otherwise
4041 */
4042
4043int
4044xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4045 xmlAttributePtr attr) {
4046 int ret = 1;
4047 int val;
4048 CHECK_DTD;
4049 if(attr == NULL) return(1);
4050
4051 /* Attribute Default Legal */
4052 /* Enumeration */
4053 if (attr->defaultValue != NULL) {
4054 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
4055 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004056 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004057 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004058 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004059 }
4060 ret &= val;
4061 }
4062
4063 /* ID Attribute Default */
4064 if ((attr->atype == XML_ATTRIBUTE_ID)&&
4065 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4066 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004067 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004068 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004069 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004070 ret = 0;
4071 }
4072
4073 /* One ID per Element Type */
4074 if (attr->atype == XML_ATTRIBUTE_ID) {
4075 int nbId;
4076
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004077 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00004078 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4079 attr->elem);
4080 if (elem != NULL) {
Daniel Veillarddbee0f12005-06-27 13:42:57 +00004081 nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00004082 } else {
4083 xmlAttributeTablePtr table;
4084
4085 /*
4086 * The attribute may be declared in the internal subset and the
4087 * element in the external subset.
4088 */
4089 nbId = 0;
Daniel Veillard11ce4002006-03-10 00:36:23 +00004090 if (doc->intSubset != NULL) {
4091 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4092 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
4093 xmlValidateAttributeIdCallback, &nbId);
4094 }
Owen Taylor3473f882001-02-23 17:55:21 +00004095 }
4096 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004097
4098 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004099 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4100 attr->elem, nbId, attr->name);
4101 } else if (doc->extSubset != NULL) {
4102 int extId = 0;
4103 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4104 if (elem != NULL) {
Daniel Veillarddbee0f12005-06-27 13:42:57 +00004105 extId = xmlScanIDAttributeDecl(NULL, elem, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00004106 }
4107 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004108 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004109 "Element %s has %d ID attribute defined in the external subset : %s\n",
4110 attr->elem, extId, attr->name);
4111 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004112 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004113"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004114 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004115 }
4116 }
4117 }
4118
4119 /* Validity Constraint: Enumeration */
4120 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4121 xmlEnumerationPtr tree = attr->tree;
4122 while (tree != NULL) {
4123 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4124 tree = tree->next;
4125 }
4126 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004127 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004128"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004129 attr->defaultValue, attr->name, attr->elem);
4130 ret = 0;
4131 }
4132 }
4133
4134 return(ret);
4135}
4136
4137/**
4138 * xmlValidateElementDecl:
4139 * @ctxt: the validation context
4140 * @doc: a document instance
4141 * @elem: an element definition
4142 *
4143 * Try to validate a single element definition
4144 * basically it does the following checks as described by the
4145 * XML-1.0 recommendation:
4146 * - [ VC: One ID per Element Type ]
4147 * - [ VC: No Duplicate Types ]
4148 * - [ VC: Unique Element Type Declaration ]
4149 *
4150 * returns 1 if valid or 0 otherwise
4151 */
4152
4153int
4154xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4155 xmlElementPtr elem) {
4156 int ret = 1;
4157 xmlElementPtr tst;
4158
4159 CHECK_DTD;
4160
4161 if (elem == NULL) return(1);
4162
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004163#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00004164#ifdef LIBXML_REGEXP_ENABLED
4165 /* Build the regexp associated to the content model */
4166 ret = xmlValidBuildContentModel(ctxt, elem);
4167#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004168#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00004169
Owen Taylor3473f882001-02-23 17:55:21 +00004170 /* No Duplicate Types */
4171 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4172 xmlElementContentPtr cur, next;
4173 const xmlChar *name;
4174
4175 cur = elem->content;
4176 while (cur != NULL) {
4177 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4178 if (cur->c1 == NULL) break;
4179 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4180 name = cur->c1->name;
4181 next = cur->c2;
4182 while (next != NULL) {
4183 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00004184 if ((xmlStrEqual(next->name, name)) &&
4185 (xmlStrEqual(next->prefix, cur->prefix))) {
4186 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004187 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00004188 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004189 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004190 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004191 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004192 "Definition of %s has duplicate references of %s:%s\n",
4193 elem->name, cur->prefix, name);
4194 }
Owen Taylor3473f882001-02-23 17:55:21 +00004195 ret = 0;
4196 }
4197 break;
4198 }
4199 if (next->c1 == NULL) break;
4200 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00004201 if ((xmlStrEqual(next->c1->name, name)) &&
4202 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
4203 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004204 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004205 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004206 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004207 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004208 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004209 "Definition of %s has duplicate references to %s:%s\n",
4210 elem->name, cur->prefix, name);
4211 }
Owen Taylor3473f882001-02-23 17:55:21 +00004212 ret = 0;
4213 }
4214 next = next->c2;
4215 }
4216 }
4217 cur = cur->c2;
4218 }
4219 }
4220
4221 /* VC: Unique Element Type Declaration */
4222 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004223 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004224 ((tst->prefix == elem->prefix) ||
4225 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004226 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004227 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4228 "Redefinition of element %s\n",
4229 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004230 ret = 0;
4231 }
4232 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004233 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004234 ((tst->prefix == elem->prefix) ||
4235 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004236 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004237 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4238 "Redefinition of element %s\n",
4239 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004240 ret = 0;
4241 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004242 /* One ID per Element Type
4243 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004244 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4245 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004246 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004247 return(ret);
4248}
4249
4250/**
4251 * xmlValidateOneAttribute:
4252 * @ctxt: the validation context
4253 * @doc: a document instance
4254 * @elem: an element instance
4255 * @attr: an attribute instance
4256 * @value: the attribute value (without entities processing)
4257 *
4258 * Try to validate a single attribute for an element
4259 * basically it does the following checks as described by the
4260 * XML-1.0 recommendation:
4261 * - [ VC: Attribute Value Type ]
4262 * - [ VC: Fixed Attribute Default ]
4263 * - [ VC: Entity Name ]
4264 * - [ VC: Name Token ]
4265 * - [ VC: ID ]
4266 * - [ VC: IDREF ]
4267 * - [ VC: Entity Name ]
4268 * - [ VC: Notation Attributes ]
4269 *
4270 * The ID/IDREF uniqueness and matching are done separately
4271 *
4272 * returns 1 if valid or 0 otherwise
4273 */
4274
4275int
4276xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004277 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4278{
Owen Taylor3473f882001-02-23 17:55:21 +00004279 xmlAttributePtr attrDecl = NULL;
4280 int val;
4281 int ret = 1;
4282
4283 CHECK_DTD;
4284 if ((elem == NULL) || (elem->name == NULL)) return(0);
4285 if ((attr == NULL) || (attr->name == NULL)) return(0);
4286
4287 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004288 xmlChar fn[50];
4289 xmlChar *fullname;
4290
4291 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4292 if (fullname == NULL)
4293 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004294 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004295 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004296 attr->name, attr->ns->prefix);
4297 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004298 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004299 attr->name, attr->ns->prefix);
4300 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004301 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004302 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4303 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004304 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004305 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004306 if ((fullname != fn) && (fullname != elem->name))
4307 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004308 }
4309 if (attrDecl == NULL) {
4310 if (attr->ns != NULL) {
4311 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4312 attr->name, attr->ns->prefix);
4313 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4314 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4315 attr->name, attr->ns->prefix);
4316 } else {
4317 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4318 elem->name, attr->name);
4319 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4320 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4321 elem->name, attr->name);
4322 }
4323 }
4324
4325
4326 /* Validity Constraint: Attribute Value Type */
4327 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004328 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004329 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004330 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004331 return(0);
4332 }
4333 attr->atype = attrDecl->atype;
4334
4335 val = xmlValidateAttributeValue(attrDecl->atype, value);
4336 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004337 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004338 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004339 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004340 ret = 0;
4341 }
4342
4343 /* Validity constraint: Fixed Attribute Default */
4344 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4345 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004346 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004347 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004348 attr->name, elem->name, attrDecl->defaultValue);
4349 ret = 0;
4350 }
4351 }
4352
4353 /* Validity Constraint: ID uniqueness */
4354 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4355 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4356 ret = 0;
4357 }
4358
4359 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4360 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4361 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4362 ret = 0;
4363 }
4364
4365 /* Validity Constraint: Notation Attributes */
4366 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4367 xmlEnumerationPtr tree = attrDecl->tree;
4368 xmlNotationPtr nota;
4369
4370 /* First check that the given NOTATION was declared */
4371 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4372 if (nota == NULL)
4373 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4374
4375 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004376 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004377 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004378 value, attr->name, elem->name);
4379 ret = 0;
4380 }
4381
4382 /* Second, verify that it's among the list */
4383 while (tree != NULL) {
4384 if (xmlStrEqual(tree->name, value)) break;
4385 tree = tree->next;
4386 }
4387 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004388 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004389"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004390 value, attr->name, elem->name);
4391 ret = 0;
4392 }
4393 }
4394
4395 /* Validity Constraint: Enumeration */
4396 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4397 xmlEnumerationPtr tree = attrDecl->tree;
4398 while (tree != NULL) {
4399 if (xmlStrEqual(tree->name, value)) break;
4400 tree = tree->next;
4401 }
4402 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004403 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004404 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004405 value, attr->name, elem->name);
4406 ret = 0;
4407 }
4408 }
4409
4410 /* Fixed Attribute Default */
4411 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4412 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004413 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004414 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004415 attr->name, elem->name, attrDecl->defaultValue);
4416 ret = 0;
4417 }
4418
4419 /* Extra check for the attribute value */
4420 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4421 attrDecl->atype, value);
4422
4423 return(ret);
4424}
4425
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004426/**
4427 * xmlValidateOneNamespace:
4428 * @ctxt: the validation context
4429 * @doc: a document instance
4430 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004431 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004432 * @ns: an namespace declaration instance
4433 * @value: the attribute value (without entities processing)
4434 *
4435 * Try to validate a single namespace declaration for an element
4436 * basically it does the following checks as described by the
4437 * XML-1.0 recommendation:
4438 * - [ VC: Attribute Value Type ]
4439 * - [ VC: Fixed Attribute Default ]
4440 * - [ VC: Entity Name ]
4441 * - [ VC: Name Token ]
4442 * - [ VC: ID ]
4443 * - [ VC: IDREF ]
4444 * - [ VC: Entity Name ]
4445 * - [ VC: Notation Attributes ]
4446 *
4447 * The ID/IDREF uniqueness and matching are done separately
4448 *
4449 * returns 1 if valid or 0 otherwise
4450 */
4451
4452int
4453xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4454xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4455 /* xmlElementPtr elemDecl; */
4456 xmlAttributePtr attrDecl = NULL;
4457 int val;
4458 int ret = 1;
4459
4460 CHECK_DTD;
4461 if ((elem == NULL) || (elem->name == NULL)) return(0);
4462 if ((ns == NULL) || (ns->href == NULL)) return(0);
4463
4464 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004465 xmlChar fn[50];
4466 xmlChar *fullname;
4467
4468 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4469 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004470 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004471 return(0);
4472 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004473 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004474 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004475 ns->prefix, BAD_CAST "xmlns");
4476 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004477 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004478 ns->prefix, BAD_CAST "xmlns");
4479 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004480 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004481 BAD_CAST "xmlns");
4482 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004483 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004484 BAD_CAST "xmlns");
4485 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004486 if ((fullname != fn) && (fullname != elem->name))
4487 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004488 }
4489 if (attrDecl == NULL) {
4490 if (ns->prefix != NULL) {
4491 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4492 ns->prefix, BAD_CAST "xmlns");
4493 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4494 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4495 ns->prefix, BAD_CAST "xmlns");
4496 } else {
4497 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4498 elem->name, BAD_CAST "xmlns");
4499 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4500 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4501 elem->name, BAD_CAST "xmlns");
4502 }
4503 }
4504
4505
4506 /* Validity Constraint: Attribute Value Type */
4507 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004508 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004509 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004510 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004511 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004512 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004513 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004514 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004515 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004516 }
4517 return(0);
4518 }
4519
4520 val = xmlValidateAttributeValue(attrDecl->atype, value);
4521 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004522 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004523 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004524 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004525 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004526 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004527 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004528 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004529 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004530 }
4531 ret = 0;
4532 }
4533
4534 /* Validity constraint: Fixed Attribute Default */
4535 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4536 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004537 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004538 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004539 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4540 ns->prefix, elem->name, attrDecl->defaultValue);
4541 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004542 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004543 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004544 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004545 }
4546 ret = 0;
4547 }
4548 }
4549
4550 /* Validity Constraint: ID uniqueness */
4551 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4552 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4553 ret = 0;
4554 }
4555
4556 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4557 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4558 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4559 ret = 0;
4560 }
4561
4562 /* Validity Constraint: Notation Attributes */
4563 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4564 xmlEnumerationPtr tree = attrDecl->tree;
4565 xmlNotationPtr nota;
4566
4567 /* First check that the given NOTATION was declared */
4568 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4569 if (nota == NULL)
4570 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4571
4572 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004573 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004574 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004575 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4576 value, ns->prefix, elem->name);
4577 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004578 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004579 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004580 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004581 }
4582 ret = 0;
4583 }
4584
4585 /* Second, verify that it's among the list */
4586 while (tree != NULL) {
4587 if (xmlStrEqual(tree->name, value)) break;
4588 tree = tree->next;
4589 }
4590 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004591 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004592 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004593"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4594 value, ns->prefix, elem->name);
4595 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004596 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004597"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004598 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004599 }
4600 ret = 0;
4601 }
4602 }
4603
4604 /* Validity Constraint: Enumeration */
4605 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4606 xmlEnumerationPtr tree = attrDecl->tree;
4607 while (tree != NULL) {
4608 if (xmlStrEqual(tree->name, value)) break;
4609 tree = tree->next;
4610 }
4611 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004612 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004613 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004614"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4615 value, ns->prefix, elem->name);
4616 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004617 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004618"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004619 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004620 }
4621 ret = 0;
4622 }
4623 }
4624
4625 /* Fixed Attribute Default */
4626 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4627 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004628 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004629 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004630 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4631 ns->prefix, elem->name, attrDecl->defaultValue);
4632 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004633 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004634 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004635 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004636 }
4637 ret = 0;
4638 }
4639
4640 /* Extra check for the attribute value */
4641 if (ns->prefix != NULL) {
4642 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4643 attrDecl->atype, value);
4644 } else {
4645 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4646 attrDecl->atype, value);
4647 }
4648
4649 return(ret);
4650}
4651
Daniel Veillard118aed72002-09-24 14:13:13 +00004652#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004653/**
4654 * xmlValidateSkipIgnorable:
4655 * @ctxt: the validation context
4656 * @child: the child list
4657 *
4658 * Skip ignorable elements w.r.t. the validation process
4659 *
4660 * returns the first element to consider for validation of the content model
4661 */
4662
4663static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004664xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004665 while (child != NULL) {
4666 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004667 /* These things are ignored (skipped) during validation. */
4668 case XML_PI_NODE:
4669 case XML_COMMENT_NODE:
4670 case XML_XINCLUDE_START:
4671 case XML_XINCLUDE_END:
4672 child = child->next;
4673 break;
4674 case XML_TEXT_NODE:
4675 if (xmlIsBlankNode(child))
4676 child = child->next;
4677 else
4678 return(child);
4679 break;
4680 /* keep current node */
4681 default:
4682 return(child);
4683 }
4684 }
4685 return(child);
4686}
4687
4688/**
4689 * xmlValidateElementType:
4690 * @ctxt: the validation context
4691 *
4692 * Try to validate the content model of an element internal function
4693 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004694 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4695 * reference is found and -3 if the validation succeeded but
4696 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004697 */
4698
4699static int
4700xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004701 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004702 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004703
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004704 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004705 if ((NODE == NULL) && (CONT == NULL))
4706 return(1);
4707 if ((NODE == NULL) &&
4708 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4709 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4710 return(1);
4711 }
4712 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004713 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004714 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004715
4716 /*
4717 * We arrive here when more states need to be examined
4718 */
4719cont:
4720
4721 /*
4722 * We just recovered from a rollback generated by a possible
4723 * epsilon transition, go directly to the analysis phase
4724 */
4725 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004726 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004727 DEBUG_VALID_STATE(NODE, CONT)
4728 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004729 goto analyze;
4730 }
4731
4732 DEBUG_VALID_STATE(NODE, CONT)
4733 /*
4734 * we may have to save a backup state here. This is the equivalent
4735 * of handling epsilon transition in NFAs.
4736 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004737 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004738 ((CONT->parent == NULL) ||
4739 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004740 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004741 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004742 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004743 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004744 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4745 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004746 }
4747
4748
4749 /*
4750 * Check first if the content matches
4751 */
4752 switch (CONT->type) {
4753 case XML_ELEMENT_CONTENT_PCDATA:
4754 if (NODE == NULL) {
4755 DEBUG_VALID_MSG("pcdata failed no node");
4756 ret = 0;
4757 break;
4758 }
4759 if (NODE->type == XML_TEXT_NODE) {
4760 DEBUG_VALID_MSG("pcdata found, skip to next");
4761 /*
4762 * go to next element in the content model
4763 * skipping ignorable elems
4764 */
4765 do {
4766 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004767 NODE = xmlValidateSkipIgnorable(NODE);
4768 if ((NODE != NULL) &&
4769 (NODE->type == XML_ENTITY_REF_NODE))
4770 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004771 } while ((NODE != NULL) &&
4772 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004773 (NODE->type != XML_TEXT_NODE) &&
4774 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004775 ret = 1;
4776 break;
4777 } else {
4778 DEBUG_VALID_MSG("pcdata failed");
4779 ret = 0;
4780 break;
4781 }
4782 break;
4783 case XML_ELEMENT_CONTENT_ELEMENT:
4784 if (NODE == NULL) {
4785 DEBUG_VALID_MSG("element failed no node");
4786 ret = 0;
4787 break;
4788 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004789 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4790 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004791 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004792 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4793 ret = (CONT->prefix == NULL);
4794 } else if (CONT->prefix == NULL) {
4795 ret = 0;
4796 } else {
4797 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4798 }
4799 }
4800 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004801 DEBUG_VALID_MSG("element found, skip to next");
4802 /*
4803 * go to next element in the content model
4804 * skipping ignorable elems
4805 */
4806 do {
4807 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004808 NODE = xmlValidateSkipIgnorable(NODE);
4809 if ((NODE != NULL) &&
4810 (NODE->type == XML_ENTITY_REF_NODE))
4811 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004812 } while ((NODE != NULL) &&
4813 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004814 (NODE->type != XML_TEXT_NODE) &&
4815 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004816 } else {
4817 DEBUG_VALID_MSG("element failed");
4818 ret = 0;
4819 break;
4820 }
4821 break;
4822 case XML_ELEMENT_CONTENT_OR:
4823 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004824 * Small optimization.
4825 */
4826 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4827 if ((NODE == NULL) ||
4828 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4829 DEPTH++;
4830 CONT = CONT->c2;
4831 goto cont;
4832 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004833 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4834 ret = (CONT->c1->prefix == NULL);
4835 } else if (CONT->c1->prefix == NULL) {
4836 ret = 0;
4837 } else {
4838 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4839 }
4840 if (ret == 0) {
4841 DEPTH++;
4842 CONT = CONT->c2;
4843 goto cont;
4844 }
Daniel Veillard85349052001-04-20 13:48:21 +00004845 }
4846
4847 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004848 * save the second branch 'or' branch
4849 */
4850 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004851 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4852 OCCURS, ROLLBACK_OR) < 0)
4853 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004854 DEPTH++;
4855 CONT = CONT->c1;
4856 goto cont;
4857 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004858 /*
4859 * Small optimization.
4860 */
4861 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4862 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4863 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4864 if ((NODE == NULL) ||
4865 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4866 DEPTH++;
4867 CONT = CONT->c2;
4868 goto cont;
4869 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004870 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4871 ret = (CONT->c1->prefix == NULL);
4872 } else if (CONT->c1->prefix == NULL) {
4873 ret = 0;
4874 } else {
4875 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4876 }
4877 if (ret == 0) {
4878 DEPTH++;
4879 CONT = CONT->c2;
4880 goto cont;
4881 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004882 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004883 DEPTH++;
4884 CONT = CONT->c1;
4885 goto cont;
4886 }
4887
4888 /*
4889 * At this point handle going up in the tree
4890 */
4891 if (ret == -1) {
4892 DEBUG_VALID_MSG("error found returning");
4893 return(ret);
4894 }
4895analyze:
4896 while (CONT != NULL) {
4897 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004898 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004899 * this level.
4900 */
4901 if (ret == 0) {
4902 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004903 xmlNodePtr cur;
4904
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004905 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004906 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004907 DEBUG_VALID_MSG("Once branch failed, rollback");
4908 if (vstateVPop(ctxt) < 0 ) {
4909 DEBUG_VALID_MSG("exhaustion, failed");
4910 return(0);
4911 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004912 if (cur != ctxt->vstate->node)
4913 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004914 goto cont;
4915 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004916 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004917 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004918 DEBUG_VALID_MSG("Plus branch failed, rollback");
4919 if (vstateVPop(ctxt) < 0 ) {
4920 DEBUG_VALID_MSG("exhaustion, failed");
4921 return(0);
4922 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004923 if (cur != ctxt->vstate->node)
4924 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004925 goto cont;
4926 }
4927 DEBUG_VALID_MSG("Plus branch found");
4928 ret = 1;
4929 break;
4930 case XML_ELEMENT_CONTENT_MULT:
4931#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004932 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004933 DEBUG_VALID_MSG("Mult branch failed");
4934 } else {
4935 DEBUG_VALID_MSG("Mult branch found");
4936 }
4937#endif
4938 ret = 1;
4939 break;
4940 case XML_ELEMENT_CONTENT_OPT:
4941 DEBUG_VALID_MSG("Option branch failed");
4942 ret = 1;
4943 break;
4944 }
4945 } else {
4946 switch (CONT->ocur) {
4947 case XML_ELEMENT_CONTENT_OPT:
4948 DEBUG_VALID_MSG("Option branch succeeded");
4949 ret = 1;
4950 break;
4951 case XML_ELEMENT_CONTENT_ONCE:
4952 DEBUG_VALID_MSG("Once branch succeeded");
4953 ret = 1;
4954 break;
4955 case XML_ELEMENT_CONTENT_PLUS:
4956 if (STATE == ROLLBACK_PARENT) {
4957 DEBUG_VALID_MSG("Plus branch rollback");
4958 ret = 1;
4959 break;
4960 }
4961 if (NODE == NULL) {
4962 DEBUG_VALID_MSG("Plus branch exhausted");
4963 ret = 1;
4964 break;
4965 }
4966 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004967 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004968 goto cont;
4969 case XML_ELEMENT_CONTENT_MULT:
4970 if (STATE == ROLLBACK_PARENT) {
4971 DEBUG_VALID_MSG("Mult branch rollback");
4972 ret = 1;
4973 break;
4974 }
4975 if (NODE == NULL) {
4976 DEBUG_VALID_MSG("Mult branch exhausted");
4977 ret = 1;
4978 break;
4979 }
4980 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004981 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004982 goto cont;
4983 }
4984 }
4985 STATE = 0;
4986
4987 /*
4988 * Then act accordingly at the parent level
4989 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004990 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004991 if (CONT->parent == NULL)
4992 break;
4993
4994 switch (CONT->parent->type) {
4995 case XML_ELEMENT_CONTENT_PCDATA:
4996 DEBUG_VALID_MSG("Error: parent pcdata");
4997 return(-1);
4998 case XML_ELEMENT_CONTENT_ELEMENT:
4999 DEBUG_VALID_MSG("Error: parent element");
5000 return(-1);
5001 case XML_ELEMENT_CONTENT_OR:
5002 if (ret == 1) {
5003 DEBUG_VALID_MSG("Or succeeded");
5004 CONT = CONT->parent;
5005 DEPTH--;
5006 } else {
5007 DEBUG_VALID_MSG("Or failed");
5008 CONT = CONT->parent;
5009 DEPTH--;
5010 }
5011 break;
5012 case XML_ELEMENT_CONTENT_SEQ:
5013 if (ret == 0) {
5014 DEBUG_VALID_MSG("Sequence failed");
5015 CONT = CONT->parent;
5016 DEPTH--;
5017 } else if (CONT == CONT->parent->c1) {
5018 DEBUG_VALID_MSG("Sequence testing 2nd branch");
5019 CONT = CONT->parent->c2;
5020 goto cont;
5021 } else {
5022 DEBUG_VALID_MSG("Sequence succeeded");
5023 CONT = CONT->parent;
5024 DEPTH--;
5025 }
5026 }
5027 }
5028 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005029 xmlNodePtr cur;
5030
5031 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005032 DEBUG_VALID_MSG("Failed, remaining input, rollback");
5033 if (vstateVPop(ctxt) < 0 ) {
5034 DEBUG_VALID_MSG("exhaustion, failed");
5035 return(0);
5036 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005037 if (cur != ctxt->vstate->node)
5038 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005039 goto cont;
5040 }
5041 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005042 xmlNodePtr cur;
5043
5044 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005045 DEBUG_VALID_MSG("Failure, rollback");
5046 if (vstateVPop(ctxt) < 0 ) {
5047 DEBUG_VALID_MSG("exhaustion, failed");
5048 return(0);
5049 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005050 if (cur != ctxt->vstate->node)
5051 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005052 goto cont;
5053 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005054 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005055}
Daniel Veillard23e73572002-09-19 19:56:43 +00005056#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005057
5058/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00005059 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005060 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00005061 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005062 * @content: An element
5063 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5064 *
5065 * This will dump the list of elements to the buffer
5066 * Intended just for the debug routine
5067 */
5068static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00005069xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005070 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00005071 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005072
5073 if (node == NULL) return;
5074 if (glob) strcat(buf, "(");
5075 cur = node;
5076 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005077 len = strlen(buf);
5078 if (size - len < 50) {
5079 if ((size - len > 4) && (buf[len - 1] != '.'))
5080 strcat(buf, " ...");
5081 return;
5082 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005083 switch (cur->type) {
5084 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005085 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005086 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005087 if ((size - len > 4) && (buf[len - 1] != '.'))
5088 strcat(buf, " ...");
5089 return;
5090 }
5091 strcat(buf, (char *) cur->ns->prefix);
5092 strcat(buf, ":");
5093 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005094 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005095 if ((size - len > 4) && (buf[len - 1] != '.'))
5096 strcat(buf, " ...");
5097 return;
5098 }
5099 strcat(buf, (char *) cur->name);
5100 if (cur->next != NULL)
5101 strcat(buf, " ");
5102 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005103 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005104 if (xmlIsBlankNode(cur))
5105 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005106 case XML_CDATA_SECTION_NODE:
5107 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005108 strcat(buf, "CDATA");
5109 if (cur->next != NULL)
5110 strcat(buf, " ");
5111 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005112 case XML_ATTRIBUTE_NODE:
5113 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005114#ifdef LIBXML_DOCB_ENABLED
5115 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005116#endif
5117 case XML_HTML_DOCUMENT_NODE:
5118 case XML_DOCUMENT_TYPE_NODE:
5119 case XML_DOCUMENT_FRAG_NODE:
5120 case XML_NOTATION_NODE:
5121 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005122 strcat(buf, "???");
5123 if (cur->next != NULL)
5124 strcat(buf, " ");
5125 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005126 case XML_ENTITY_NODE:
5127 case XML_PI_NODE:
5128 case XML_DTD_NODE:
5129 case XML_COMMENT_NODE:
5130 case XML_ELEMENT_DECL:
5131 case XML_ATTRIBUTE_DECL:
5132 case XML_ENTITY_DECL:
5133 case XML_XINCLUDE_START:
5134 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005135 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005136 }
5137 cur = cur->next;
5138 }
5139 if (glob) strcat(buf, ")");
5140}
5141
5142/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005143 * xmlValidateElementContent:
5144 * @ctxt: the validation context
5145 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005146 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005147 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005148 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005149 *
5150 * Try to validate the content model of an element
5151 *
5152 * returns 1 if valid or 0 if not and -1 in case of error
5153 */
5154
5155static int
5156xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005157 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00005158 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00005159#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00005160 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00005161#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00005162 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005163 xmlElementContentPtr cont;
5164 const xmlChar *name;
5165
5166 if (elemDecl == NULL)
5167 return(-1);
5168 cont = elemDecl->content;
5169 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005170
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005171#ifdef LIBXML_REGEXP_ENABLED
5172 /* Build the regexp associated to the content model */
5173 if (elemDecl->contModel == NULL)
5174 ret = xmlValidBuildContentModel(ctxt, elemDecl);
5175 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005176 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005177 } else {
5178 xmlRegExecCtxtPtr exec;
5179
Daniel Veillardec498e12003-02-05 11:01:50 +00005180 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5181 return(-1);
5182 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005183 ctxt->nodeMax = 0;
5184 ctxt->nodeNr = 0;
5185 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005186 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5187 if (exec != NULL) {
5188 cur = child;
5189 while (cur != NULL) {
5190 switch (cur->type) {
5191 case XML_ENTITY_REF_NODE:
5192 /*
5193 * Push the current node to be able to roll back
5194 * and process within the entity
5195 */
5196 if ((cur->children != NULL) &&
5197 (cur->children->children != NULL)) {
5198 nodeVPush(ctxt, cur);
5199 cur = cur->children->children;
5200 continue;
5201 }
5202 break;
5203 case XML_TEXT_NODE:
5204 if (xmlIsBlankNode(cur))
5205 break;
5206 ret = 0;
5207 goto fail;
5208 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00005209 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005210 ret = 0;
5211 goto fail;
5212 case XML_ELEMENT_NODE:
5213 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005214 xmlChar fn[50];
5215 xmlChar *fullname;
5216
5217 fullname = xmlBuildQName(cur->name,
5218 cur->ns->prefix, fn, 50);
5219 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005220 ret = -1;
5221 goto fail;
5222 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005223 ret = xmlRegExecPushString(exec, fullname, NULL);
5224 if ((fullname != fn) && (fullname != cur->name))
5225 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005226 } else {
5227 ret = xmlRegExecPushString(exec, cur->name, NULL);
5228 }
5229 break;
5230 default:
5231 break;
5232 }
5233 /*
5234 * Switch to next element
5235 */
5236 cur = cur->next;
5237 while (cur == NULL) {
5238 cur = nodeVPop(ctxt);
5239 if (cur == NULL)
5240 break;
5241 cur = cur->next;
5242 }
5243 }
5244 ret = xmlRegExecPushString(exec, NULL, NULL);
5245fail:
5246 xmlRegFreeExecCtxt(exec);
5247 }
5248 }
5249#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005250 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005251 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005252 */
5253 ctxt->vstateMax = 8;
5254 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5255 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5256 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005257 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005258 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005259 }
5260 /*
5261 * The first entry in the stack is reserved to the current state
5262 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005263 ctxt->nodeMax = 0;
5264 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005265 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005266 ctxt->vstate = &ctxt->vstateTab[0];
5267 ctxt->vstateNr = 1;
5268 CONT = cont;
5269 NODE = child;
5270 DEPTH = 0;
5271 OCCURS = 0;
5272 STATE = 0;
5273 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005274 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005275 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5276 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005277 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005278 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005279 /*
5280 * An entities reference appeared at this level.
5281 * Buid a minimal representation of this node content
5282 * sufficient to run the validation process on it
5283 */
5284 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005285 cur = child;
5286 while (cur != NULL) {
5287 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005288 case XML_ENTITY_REF_NODE:
5289 /*
5290 * Push the current node to be able to roll back
5291 * and process within the entity
5292 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005293 if ((cur->children != NULL) &&
5294 (cur->children->children != NULL)) {
5295 nodeVPush(ctxt, cur);
5296 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005297 continue;
5298 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005299 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005300 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005301 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005302 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005303 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005304 case XML_CDATA_SECTION_NODE:
5305 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005306 case XML_ELEMENT_NODE:
5307 /*
5308 * Allocate a new node and minimally fills in
5309 * what's required
5310 */
5311 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5312 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005313 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005314 xmlFreeNodeList(repl);
5315 ret = -1;
5316 goto done;
5317 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005318 tmp->type = cur->type;
5319 tmp->name = cur->name;
5320 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005321 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005322 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005323 if (repl == NULL)
5324 repl = last = tmp;
5325 else {
5326 last->next = tmp;
5327 last = tmp;
5328 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005329 if (cur->type == XML_CDATA_SECTION_NODE) {
5330 /*
5331 * E59 spaces in CDATA does not match the
5332 * nonterminal S
5333 */
5334 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5335 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005336 break;
5337 default:
5338 break;
5339 }
5340 /*
5341 * Switch to next element
5342 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005343 cur = cur->next;
5344 while (cur == NULL) {
5345 cur = nodeVPop(ctxt);
5346 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005347 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005348 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005349 }
5350 }
5351
5352 /*
5353 * Relaunch the validation
5354 */
5355 ctxt->vstate = &ctxt->vstateTab[0];
5356 ctxt->vstateNr = 1;
5357 CONT = cont;
5358 NODE = repl;
5359 DEPTH = 0;
5360 OCCURS = 0;
5361 STATE = 0;
5362 ret = xmlValidateElementType(ctxt);
5363 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005364#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005365 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00005366 if (ctxt != NULL) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005367 char expr[5000];
5368 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005369
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005370 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005371 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005372 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005373#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005374 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005375 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005376 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005377#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005378 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005379
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005380 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005381 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5382 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5383 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005384 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005385 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5386 "Element content does not follow the DTD, expecting %s, got %s\n",
5387 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005388 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005389 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005390 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005391 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005392 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005393 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005394 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005395 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5396 "Element content does not follow the DTD\n",
5397 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005398 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005399 }
5400 ret = 0;
5401 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005402 if (ret == -3)
5403 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005404
Daniel Veillard23e73572002-09-19 19:56:43 +00005405#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005406done:
5407 /*
5408 * Deallocate the copy if done, and free up the validation stack
5409 */
5410 while (repl != NULL) {
5411 tmp = repl->next;
5412 xmlFree(repl);
5413 repl = tmp;
5414 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005415 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005416 if (ctxt->vstateTab != NULL) {
5417 xmlFree(ctxt->vstateTab);
5418 ctxt->vstateTab = NULL;
5419 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005420#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005421 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005422 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005423 if (ctxt->nodeTab != NULL) {
5424 xmlFree(ctxt->nodeTab);
5425 ctxt->nodeTab = NULL;
5426 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005427 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005428
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005429}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005430
Owen Taylor3473f882001-02-23 17:55:21 +00005431/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005432 * xmlValidateCdataElement:
5433 * @ctxt: the validation context
5434 * @doc: a document instance
5435 * @elem: an element instance
5436 *
5437 * Check that an element follows #CDATA
5438 *
5439 * returns 1 if valid or 0 otherwise
5440 */
5441static int
5442xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5443 xmlNodePtr elem) {
5444 int ret = 1;
5445 xmlNodePtr cur, child;
5446
Daniel Veillardceb09b92002-10-04 11:46:37 +00005447 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005448 return(0);
5449
5450 child = elem->children;
5451
5452 cur = child;
5453 while (cur != NULL) {
5454 switch (cur->type) {
5455 case XML_ENTITY_REF_NODE:
5456 /*
5457 * Push the current node to be able to roll back
5458 * and process within the entity
5459 */
5460 if ((cur->children != NULL) &&
5461 (cur->children->children != NULL)) {
5462 nodeVPush(ctxt, cur);
5463 cur = cur->children->children;
5464 continue;
5465 }
5466 break;
5467 case XML_COMMENT_NODE:
5468 case XML_PI_NODE:
5469 case XML_TEXT_NODE:
5470 case XML_CDATA_SECTION_NODE:
5471 break;
5472 default:
5473 ret = 0;
5474 goto done;
5475 }
5476 /*
5477 * Switch to next element
5478 */
5479 cur = cur->next;
5480 while (cur == NULL) {
5481 cur = nodeVPop(ctxt);
5482 if (cur == NULL)
5483 break;
5484 cur = cur->next;
5485 }
5486 }
5487done:
5488 ctxt->nodeMax = 0;
5489 ctxt->nodeNr = 0;
5490 if (ctxt->nodeTab != NULL) {
5491 xmlFree(ctxt->nodeTab);
5492 ctxt->nodeTab = NULL;
5493 }
5494 return(ret);
5495}
5496
5497/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005498 * xmlValidateCheckMixed:
5499 * @ctxt: the validation context
5500 * @cont: the mixed content model
5501 * @qname: the qualified name as appearing in the serialization
5502 *
5503 * Check if the given node is part of the content model.
5504 *
5505 * Returns 1 if yes, 0 if no, -1 in case of error
5506 */
5507static int
William M. Brackedb65a72004-02-06 07:36:04 +00005508xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005509 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005510 const xmlChar *name;
5511 int plen;
5512 name = xmlSplitQName3(qname, &plen);
5513
5514 if (name == NULL) {
5515 while (cont != NULL) {
5516 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5517 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5518 return(1);
5519 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5520 (cont->c1 != NULL) &&
5521 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5522 if ((cont->c1->prefix == NULL) &&
5523 (xmlStrEqual(cont->c1->name, qname)))
5524 return(1);
5525 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5526 (cont->c1 == NULL) ||
5527 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005528 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5529 "Internal: MIXED struct corrupted\n",
5530 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005531 break;
5532 }
5533 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005534 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005535 } else {
5536 while (cont != NULL) {
5537 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5538 if ((cont->prefix != NULL) &&
5539 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5540 (xmlStrEqual(cont->name, name)))
5541 return(1);
5542 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5543 (cont->c1 != NULL) &&
5544 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5545 if ((cont->c1->prefix != NULL) &&
5546 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5547 (xmlStrEqual(cont->c1->name, name)))
5548 return(1);
5549 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5550 (cont->c1 == NULL) ||
5551 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005552 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5553 "Internal: MIXED struct corrupted\n",
5554 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005555 break;
5556 }
5557 cont = cont->c2;
5558 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005559 }
5560 return(0);
5561}
5562
5563/**
5564 * xmlValidGetElemDecl:
5565 * @ctxt: the validation context
5566 * @doc: a document instance
5567 * @elem: an element instance
5568 * @extsubset: pointer, (out) indicate if the declaration was found
5569 * in the external subset.
5570 *
5571 * Finds a declaration associated to an element in the document.
5572 *
5573 * returns the pointer to the declaration or NULL if not found.
5574 */
5575static xmlElementPtr
5576xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5577 xmlNodePtr elem, int *extsubset) {
5578 xmlElementPtr elemDecl = NULL;
5579 const xmlChar *prefix = NULL;
5580
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005581 if ((ctxt == NULL) || (doc == NULL) ||
5582 (elem == NULL) || (elem->name == NULL))
5583 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005584 if (extsubset != NULL)
5585 *extsubset = 0;
5586
5587 /*
5588 * Fetch the declaration for the qualified name
5589 */
5590 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5591 prefix = elem->ns->prefix;
5592
5593 if (prefix != NULL) {
5594 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5595 elem->name, prefix);
5596 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5597 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5598 elem->name, prefix);
5599 if ((elemDecl != NULL) && (extsubset != NULL))
5600 *extsubset = 1;
5601 }
5602 }
5603
5604 /*
5605 * Fetch the declaration for the non qualified name
5606 * This is "non-strict" validation should be done on the
5607 * full QName but in that case being flexible makes sense.
5608 */
5609 if (elemDecl == NULL) {
5610 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5611 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5612 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5613 if ((elemDecl != NULL) && (extsubset != NULL))
5614 *extsubset = 1;
5615 }
5616 }
5617 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005618 xmlErrValidNode(ctxt, elem,
5619 XML_DTD_UNKNOWN_ELEM,
5620 "No declaration for element %s\n",
5621 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005622 }
5623 return(elemDecl);
5624}
5625
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005626#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005627/**
5628 * xmlValidatePushElement:
5629 * @ctxt: the validation context
5630 * @doc: a document instance
5631 * @elem: an element instance
5632 * @qname: the qualified name as appearing in the serialization
5633 *
5634 * Push a new element start on the validation stack.
5635 *
5636 * returns 1 if no validation problem was found or 0 otherwise
5637 */
5638int
5639xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5640 xmlNodePtr elem, const xmlChar *qname) {
5641 int ret = 1;
5642 xmlElementPtr eDecl;
5643 int extsubset = 0;
5644
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005645 if (ctxt == NULL)
5646 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005647/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005648 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5649 xmlValidStatePtr state = ctxt->vstate;
5650 xmlElementPtr elemDecl;
5651
5652 /*
5653 * Check the new element agaisnt the content model of the new elem.
5654 */
5655 if (state->elemDecl != NULL) {
5656 elemDecl = state->elemDecl;
5657
5658 switch(elemDecl->etype) {
5659 case XML_ELEMENT_TYPE_UNDEFINED:
5660 ret = 0;
5661 break;
5662 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005663 xmlErrValidNode(ctxt, state->node,
5664 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005665 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005666 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005667 ret = 0;
5668 break;
5669 case XML_ELEMENT_TYPE_ANY:
5670 /* I don't think anything is required then */
5671 break;
5672 case XML_ELEMENT_TYPE_MIXED:
5673 /* simple case of declared as #PCDATA */
5674 if ((elemDecl->content != NULL) &&
5675 (elemDecl->content->type ==
5676 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005677 xmlErrValidNode(ctxt, state->node,
5678 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005679 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005680 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005681 ret = 0;
5682 } else {
5683 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5684 qname);
5685 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005686 xmlErrValidNode(ctxt, state->node,
5687 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005688 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005689 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005690 }
5691 }
5692 break;
5693 case XML_ELEMENT_TYPE_ELEMENT:
5694 /*
5695 * TODO:
5696 * VC: Standalone Document Declaration
5697 * - element types with element content, if white space
5698 * occurs directly within any instance of those types.
5699 */
5700 if (state->exec != NULL) {
5701 ret = xmlRegExecPushString(state->exec, qname, NULL);
5702 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005703 xmlErrValidNode(ctxt, state->node,
5704 XML_DTD_CONTENT_MODEL,
5705 "Element %s content does not follow the DTD, Misplaced %s\n",
5706 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005707 ret = 0;
5708 } else {
5709 ret = 1;
5710 }
5711 }
5712 break;
5713 }
5714 }
5715 }
5716 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5717 vstateVPush(ctxt, eDecl, elem);
5718 return(ret);
5719}
5720
5721/**
5722 * xmlValidatePushCData:
5723 * @ctxt: the validation context
5724 * @data: some character data read
5725 * @len: the lenght of the data
5726 *
5727 * check the CData parsed for validation in the current stack
5728 *
5729 * returns 1 if no validation problem was found or 0 otherwise
5730 */
5731int
5732xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5733 int ret = 1;
5734
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005735/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005736 if (ctxt == NULL)
5737 return(0);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005738 if (len <= 0)
5739 return(ret);
5740 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5741 xmlValidStatePtr state = ctxt->vstate;
5742 xmlElementPtr elemDecl;
5743
5744 /*
5745 * Check the new element agaisnt the content model of the new elem.
5746 */
5747 if (state->elemDecl != NULL) {
5748 elemDecl = state->elemDecl;
5749
5750 switch(elemDecl->etype) {
5751 case XML_ELEMENT_TYPE_UNDEFINED:
5752 ret = 0;
5753 break;
5754 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005755 xmlErrValidNode(ctxt, state->node,
5756 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005757 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005758 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005759 ret = 0;
5760 break;
5761 case XML_ELEMENT_TYPE_ANY:
5762 break;
5763 case XML_ELEMENT_TYPE_MIXED:
5764 break;
5765 case XML_ELEMENT_TYPE_ELEMENT:
5766 if (len > 0) {
5767 int i;
5768
5769 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005770 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005771 xmlErrValidNode(ctxt, state->node,
5772 XML_DTD_CONTENT_MODEL,
5773 "Element %s content does not follow the DTD, Text not allowed\n",
5774 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005775 ret = 0;
5776 goto done;
5777 }
5778 }
5779 /*
5780 * TODO:
5781 * VC: Standalone Document Declaration
5782 * element types with element content, if white space
5783 * occurs directly within any instance of those types.
5784 */
5785 }
5786 break;
5787 }
5788 }
5789 }
5790done:
5791 return(ret);
5792}
5793
5794/**
5795 * xmlValidatePopElement:
5796 * @ctxt: the validation context
5797 * @doc: a document instance
5798 * @elem: an element instance
5799 * @qname: the qualified name as appearing in the serialization
5800 *
5801 * Pop the element end from the validation stack.
5802 *
5803 * returns 1 if no validation problem was found or 0 otherwise
5804 */
5805int
5806xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005807 xmlNodePtr elem ATTRIBUTE_UNUSED,
5808 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005809 int ret = 1;
5810
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005811 if (ctxt == NULL)
5812 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005813/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005814 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5815 xmlValidStatePtr state = ctxt->vstate;
5816 xmlElementPtr elemDecl;
5817
5818 /*
5819 * Check the new element agaisnt the content model of the new elem.
5820 */
5821 if (state->elemDecl != NULL) {
5822 elemDecl = state->elemDecl;
5823
5824 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5825 if (state->exec != NULL) {
5826 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5827 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005828 xmlErrValidNode(ctxt, state->node,
5829 XML_DTD_CONTENT_MODEL,
5830 "Element %s content does not follow the DTD, Expecting more child\n",
5831 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005832 } else {
5833 /*
5834 * previous validation errors should not generate
5835 * a new one here
5836 */
5837 ret = 1;
5838 }
5839 }
5840 }
5841 }
5842 vstateVPop(ctxt);
5843 }
5844 return(ret);
5845}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005846#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005847
5848/**
Owen Taylor3473f882001-02-23 17:55:21 +00005849 * xmlValidateOneElement:
5850 * @ctxt: the validation context
5851 * @doc: a document instance
5852 * @elem: an element instance
5853 *
5854 * Try to validate a single element and it's attributes,
5855 * basically it does the following checks as described by the
5856 * XML-1.0 recommendation:
5857 * - [ VC: Element Valid ]
5858 * - [ VC: Required Attribute ]
5859 * Then call xmlValidateOneAttribute() for each attribute present.
5860 *
5861 * The ID/IDREF checkings are done separately
5862 *
5863 * returns 1 if valid or 0 otherwise
5864 */
5865
5866int
5867xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5868 xmlNodePtr elem) {
5869 xmlElementPtr elemDecl = NULL;
5870 xmlElementContentPtr cont;
5871 xmlAttributePtr attr;
5872 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005873 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005874 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005875 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005876
5877 CHECK_DTD;
5878
5879 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005880 switch (elem->type) {
5881 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005882 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5883 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005884 return(0);
5885 case XML_TEXT_NODE:
5886 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005887 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5888 "Text element has children !\n",
5889 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005890 return(0);
5891 }
Owen Taylor3473f882001-02-23 17:55:21 +00005892 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005893 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5894 "Text element has namespace !\n",
5895 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005896 return(0);
5897 }
Owen Taylor3473f882001-02-23 17:55:21 +00005898 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005899 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5900 "Text element has no content !\n",
5901 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005902 return(0);
5903 }
5904 return(1);
5905 case XML_XINCLUDE_START:
5906 case XML_XINCLUDE_END:
5907 return(1);
5908 case XML_CDATA_SECTION_NODE:
5909 case XML_ENTITY_REF_NODE:
5910 case XML_PI_NODE:
5911 case XML_COMMENT_NODE:
5912 return(1);
5913 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005914 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5915 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005916 return(0);
5917 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005918 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5919 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005920 return(0);
5921 case XML_DOCUMENT_NODE:
5922 case XML_DOCUMENT_TYPE_NODE:
5923 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005924 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5925 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005926 return(0);
5927 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005928 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5929 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005930 return(0);
5931 case XML_ELEMENT_NODE:
5932 break;
5933 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005934 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5935 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005936 return(0);
5937 }
Owen Taylor3473f882001-02-23 17:55:21 +00005938
5939 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005940 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005941 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005942 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5943 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005944 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005945
Daniel Veillardea7751d2002-12-20 00:16:24 +00005946 /*
5947 * If vstateNr is not zero that means continuous validation is
5948 * activated, do not try to check the content model at that level.
5949 */
5950 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005951 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005952 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005953 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005954 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5955 "No declaration for element %s\n",
5956 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005957 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005958 case XML_ELEMENT_TYPE_EMPTY:
5959 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005960 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005961 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005962 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005963 ret = 0;
5964 }
5965 break;
5966 case XML_ELEMENT_TYPE_ANY:
5967 /* I don't think anything is required then */
5968 break;
5969 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005970
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005971 /* simple case of declared as #PCDATA */
5972 if ((elemDecl->content != NULL) &&
5973 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5974 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5975 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005976 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005977 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005978 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005979 }
5980 break;
5981 }
Owen Taylor3473f882001-02-23 17:55:21 +00005982 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005983 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005984 while (child != NULL) {
5985 if (child->type == XML_ELEMENT_NODE) {
5986 name = child->name;
5987 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005988 xmlChar fn[50];
5989 xmlChar *fullname;
5990
5991 fullname = xmlBuildQName(child->name, child->ns->prefix,
5992 fn, 50);
5993 if (fullname == NULL)
5994 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005995 cont = elemDecl->content;
5996 while (cont != NULL) {
5997 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005998 if (xmlStrEqual(cont->name, fullname))
5999 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006000 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6001 (cont->c1 != NULL) &&
6002 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00006003 if (xmlStrEqual(cont->c1->name, fullname))
6004 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006005 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6006 (cont->c1 == NULL) ||
6007 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006008 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
6009 "Internal: MIXED struct corrupted\n",
6010 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006011 break;
6012 }
6013 cont = cont->c2;
6014 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00006015 if ((fullname != fn) && (fullname != child->name))
6016 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00006017 if (cont != NULL)
6018 goto child_ok;
6019 }
6020 cont = elemDecl->content;
6021 while (cont != NULL) {
6022 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6023 if (xmlStrEqual(cont->name, name)) break;
6024 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6025 (cont->c1 != NULL) &&
6026 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
6027 if (xmlStrEqual(cont->c1->name, name)) break;
6028 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6029 (cont->c1 == NULL) ||
6030 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006031 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
6032 "Internal: MIXED struct corrupted\n",
6033 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006034 break;
6035 }
6036 cont = cont->c2;
6037 }
6038 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006039 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006040 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006041 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006042 ret = 0;
6043 }
6044 }
6045child_ok:
6046 child = child->next;
6047 }
6048 break;
6049 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006050 if ((doc->standalone == 1) && (extsubset == 1)) {
6051 /*
6052 * VC: Standalone Document Declaration
6053 * - element types with element content, if white space
6054 * occurs directly within any instance of those types.
6055 */
6056 child = elem->children;
6057 while (child != NULL) {
6058 if (child->type == XML_TEXT_NODE) {
6059 const xmlChar *content = child->content;
6060
William M. Brack76e95df2003-10-18 16:20:14 +00006061 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006062 content++;
6063 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006064 xmlErrValidNode(ctxt, elem,
6065 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006066"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006067 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006068 ret = 0;
6069 break;
6070 }
6071 }
6072 child =child->next;
6073 }
6074 }
Owen Taylor3473f882001-02-23 17:55:21 +00006075 child = elem->children;
6076 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00006077 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006078 if (tmp <= 0)
6079 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006080 break;
6081 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00006082 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00006083
6084 /* [ VC: Required Attribute ] */
6085 attr = elemDecl->attributes;
6086 while (attr != NULL) {
6087 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006088 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006089
Daniel Veillarde4301c82002-02-13 13:32:35 +00006090 if ((attr->prefix == NULL) &&
6091 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6092 xmlNsPtr ns;
6093
6094 ns = elem->nsDef;
6095 while (ns != NULL) {
6096 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006097 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006098 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006099 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006100 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6101 xmlNsPtr ns;
6102
6103 ns = elem->nsDef;
6104 while (ns != NULL) {
6105 if (xmlStrEqual(attr->name, ns->prefix))
6106 goto found;
6107 ns = ns->next;
6108 }
6109 } else {
6110 xmlAttrPtr attrib;
6111
6112 attrib = elem->properties;
6113 while (attrib != NULL) {
6114 if (xmlStrEqual(attrib->name, attr->name)) {
6115 if (attr->prefix != NULL) {
6116 xmlNsPtr nameSpace = attrib->ns;
6117
6118 if (nameSpace == NULL)
6119 nameSpace = elem->ns;
6120 /*
6121 * qualified names handling is problematic, having a
6122 * different prefix should be possible but DTDs don't
6123 * allow to define the URI instead of the prefix :-(
6124 */
6125 if (nameSpace == NULL) {
6126 if (qualified < 0)
6127 qualified = 0;
6128 } else if (!xmlStrEqual(nameSpace->prefix,
6129 attr->prefix)) {
6130 if (qualified < 1)
6131 qualified = 1;
6132 } else
6133 goto found;
6134 } else {
6135 /*
6136 * We should allow applications to define namespaces
6137 * for their application even if the DTD doesn't
6138 * carry one, otherwise, basically we would always
6139 * break.
6140 */
6141 goto found;
6142 }
6143 }
6144 attrib = attrib->next;
6145 }
Owen Taylor3473f882001-02-23 17:55:21 +00006146 }
6147 if (qualified == -1) {
6148 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006149 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006150 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006151 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006152 ret = 0;
6153 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006154 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006155 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00006156 elem->name, attr->prefix,attr->name);
6157 ret = 0;
6158 }
6159 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006160 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006161 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006162 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006163 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006164 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006165 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006166 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006167 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006168 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
6169 /*
6170 * Special tests checking #FIXED namespace declarations
6171 * have the right value since this is not done as an
6172 * attribute checking
6173 */
6174 if ((attr->prefix == NULL) &&
6175 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6176 xmlNsPtr ns;
6177
6178 ns = elem->nsDef;
6179 while (ns != NULL) {
6180 if (ns->prefix == NULL) {
6181 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006182 xmlErrValidNode(ctxt, elem,
6183 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00006184 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006185 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006186 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006187 }
6188 goto found;
6189 }
6190 ns = ns->next;
6191 }
6192 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6193 xmlNsPtr ns;
6194
6195 ns = elem->nsDef;
6196 while (ns != NULL) {
6197 if (xmlStrEqual(attr->name, ns->prefix)) {
6198 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006199 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006200 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006201 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006202 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006203 }
6204 goto found;
6205 }
6206 ns = ns->next;
6207 }
6208 }
Owen Taylor3473f882001-02-23 17:55:21 +00006209 }
6210found:
6211 attr = attr->nexth;
6212 }
6213 return(ret);
6214}
6215
6216/**
6217 * xmlValidateRoot:
6218 * @ctxt: the validation context
6219 * @doc: a document instance
6220 *
6221 * Try to validate a the root element
6222 * basically it does the following check as described by the
6223 * XML-1.0 recommendation:
6224 * - [ VC: Root Element Type ]
6225 * it doesn't try to recurse or apply other check to the element
6226 *
6227 * returns 1 if valid or 0 otherwise
6228 */
6229
6230int
6231xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6232 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006233 int ret;
6234
Owen Taylor3473f882001-02-23 17:55:21 +00006235 if (doc == NULL) return(0);
6236
6237 root = xmlDocGetRootElement(doc);
6238 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006239 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6240 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006241 return(0);
6242 }
6243
6244 /*
6245 * When doing post validation against a separate DTD, those may
6246 * no internal subset has been generated
6247 */
6248 if ((doc->intSubset != NULL) &&
6249 (doc->intSubset->name != NULL)) {
6250 /*
6251 * Check first the document root against the NQName
6252 */
6253 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6254 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006255 xmlChar fn[50];
6256 xmlChar *fullname;
6257
6258 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6259 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006260 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006261 return(0);
6262 }
6263 ret = xmlStrEqual(doc->intSubset->name, fullname);
6264 if ((fullname != fn) && (fullname != root->name))
6265 xmlFree(fullname);
6266 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006267 goto name_ok;
6268 }
6269 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6270 (xmlStrEqual(root->name, BAD_CAST "html")))
6271 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006272 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6273 "root and DTD name do not match '%s' and '%s'\n",
6274 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006275 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006276 }
6277 }
6278name_ok:
6279 return(1);
6280}
6281
6282
6283/**
6284 * xmlValidateElement:
6285 * @ctxt: the validation context
6286 * @doc: a document instance
6287 * @elem: an element instance
6288 *
6289 * Try to validate the subtree under an element
6290 *
6291 * returns 1 if valid or 0 otherwise
6292 */
6293
6294int
6295xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6296 xmlNodePtr child;
6297 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006298 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006299 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006300 int ret = 1;
6301
6302 if (elem == NULL) return(0);
6303
6304 /*
6305 * XInclude elements were added after parsing in the infoset,
6306 * they don't really mean anything validation wise.
6307 */
6308 if ((elem->type == XML_XINCLUDE_START) ||
6309 (elem->type == XML_XINCLUDE_END))
6310 return(1);
6311
6312 CHECK_DTD;
6313
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006314 /*
6315 * Entities references have to be handled separately
6316 */
6317 if (elem->type == XML_ENTITY_REF_NODE) {
6318 return(1);
6319 }
6320
Owen Taylor3473f882001-02-23 17:55:21 +00006321 ret &= xmlValidateOneElement(ctxt, doc, elem);
Daniel Veillard8874b942005-08-25 13:19:21 +00006322 if (elem->type == XML_ELEMENT_NODE) {
6323 attr = elem->properties;
6324 while (attr != NULL) {
6325 value = xmlNodeListGetString(doc, attr->children, 0);
6326 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6327 if (value != NULL)
6328 xmlFree((char *)value);
6329 attr= attr->next;
6330 }
6331 ns = elem->nsDef;
6332 while (ns != NULL) {
6333 if (elem->ns == NULL)
6334 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6335 ns, ns->href);
6336 else
6337 ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6338 elem->ns->prefix, ns, ns->href);
6339 ns = ns->next;
6340 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006341 }
Owen Taylor3473f882001-02-23 17:55:21 +00006342 child = elem->children;
6343 while (child != NULL) {
6344 ret &= xmlValidateElement(ctxt, doc, child);
6345 child = child->next;
6346 }
6347
6348 return(ret);
6349}
6350
Daniel Veillard8730c562001-02-26 10:49:57 +00006351/**
6352 * xmlValidateRef:
6353 * @ref: A reference to be validated
6354 * @ctxt: Validation context
6355 * @name: Name of ID we are searching for
6356 *
6357 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006358static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006359xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006360 const xmlChar *name) {
6361 xmlAttrPtr id;
6362 xmlAttrPtr attr;
6363
6364 if (ref == NULL)
6365 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006366 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006367 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006368 attr = ref->attr;
6369 if (attr == NULL) {
6370 xmlChar *dup, *str = NULL, *cur, save;
6371
6372 dup = xmlStrdup(name);
6373 if (dup == NULL) {
6374 ctxt->valid = 0;
6375 return;
6376 }
6377 cur = dup;
6378 while (*cur != 0) {
6379 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006380 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006381 save = *cur;
6382 *cur = 0;
6383 id = xmlGetID(ctxt->doc, str);
6384 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006385 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006386 "attribute %s line %d references an unknown ID \"%s\"\n",
6387 ref->name, ref->lineno, str);
6388 ctxt->valid = 0;
6389 }
6390 if (save == 0)
6391 break;
6392 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006393 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006394 }
6395 xmlFree(dup);
6396 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006397 id = xmlGetID(ctxt->doc, name);
6398 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006399 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006400 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006401 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006402 ctxt->valid = 0;
6403 }
6404 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6405 xmlChar *dup, *str = NULL, *cur, save;
6406
6407 dup = xmlStrdup(name);
6408 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006409 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006410 ctxt->valid = 0;
6411 return;
6412 }
6413 cur = dup;
6414 while (*cur != 0) {
6415 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006416 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006417 save = *cur;
6418 *cur = 0;
6419 id = xmlGetID(ctxt->doc, str);
6420 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006421 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006422 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006423 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006424 ctxt->valid = 0;
6425 }
6426 if (save == 0)
6427 break;
6428 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006429 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006430 }
6431 xmlFree(dup);
6432 }
6433}
6434
6435/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006436 * xmlWalkValidateList:
6437 * @data: Contents of current link
6438 * @user: Value supplied by the user
6439 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006440 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006441 */
6442static int
6443xmlWalkValidateList(const void *data, const void *user)
6444{
6445 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6446 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6447 return 1;
6448}
6449
6450/**
6451 * xmlValidateCheckRefCallback:
6452 * @ref_list: List of references
6453 * @ctxt: Validation context
6454 * @name: Name of ID we are searching for
6455 *
6456 */
6457static void
6458xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6459 const xmlChar *name) {
6460 xmlValidateMemo memo;
6461
6462 if (ref_list == NULL)
6463 return;
6464 memo.ctxt = ctxt;
6465 memo.name = name;
6466
6467 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6468
6469}
6470
6471/**
Owen Taylor3473f882001-02-23 17:55:21 +00006472 * xmlValidateDocumentFinal:
6473 * @ctxt: the validation context
6474 * @doc: a document instance
6475 *
6476 * Does the final step for the document validation once all the
6477 * incremental validation steps have been completed
6478 *
6479 * basically it does the following checks described by the XML Rec
6480 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006481 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006482 *
6483 * returns 1 if valid or 0 otherwise
6484 */
6485
6486int
6487xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6488 xmlRefTablePtr table;
6489
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006490 if (ctxt == NULL)
6491 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006492 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006493 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6494 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006495 return(0);
6496 }
6497
6498 /*
6499 * Check all the NOTATION/NOTATIONS attributes
6500 */
6501 /*
6502 * Check all the ENTITY/ENTITIES attributes definition for validity
6503 */
6504 /*
6505 * Check all the IDREF/IDREFS attributes definition for validity
6506 */
6507 table = (xmlRefTablePtr) doc->refs;
6508 ctxt->doc = doc;
6509 ctxt->valid = 1;
6510 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6511 return(ctxt->valid);
6512}
6513
6514/**
6515 * xmlValidateDtd:
6516 * @ctxt: the validation context
6517 * @doc: a document instance
6518 * @dtd: a dtd instance
6519 *
6520 * Try to validate the document against the dtd instance
6521 *
William M. Brack367df6e2004-10-23 18:14:36 +00006522 * Basically it does check all the definitions in the DtD.
6523 * Note the the internal subset (if present) is de-coupled
6524 * (i.e. not used), which could give problems if ID or IDREF
6525 * is present.
Owen Taylor3473f882001-02-23 17:55:21 +00006526 *
6527 * returns 1 if valid or 0 otherwise
6528 */
6529
6530int
6531xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6532 int ret;
William M. Brack367df6e2004-10-23 18:14:36 +00006533 xmlDtdPtr oldExt, oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006534 xmlNodePtr root;
6535
6536 if (dtd == NULL) return(0);
6537 if (doc == NULL) return(0);
6538 oldExt = doc->extSubset;
William M. Brack367df6e2004-10-23 18:14:36 +00006539 oldInt = doc->intSubset;
Owen Taylor3473f882001-02-23 17:55:21 +00006540 doc->extSubset = dtd;
William M. Brack367df6e2004-10-23 18:14:36 +00006541 doc->intSubset = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006542 ret = xmlValidateRoot(ctxt, doc);
6543 if (ret == 0) {
6544 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006545 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006546 return(ret);
6547 }
6548 if (doc->ids != NULL) {
6549 xmlFreeIDTable(doc->ids);
6550 doc->ids = NULL;
6551 }
6552 if (doc->refs != NULL) {
6553 xmlFreeRefTable(doc->refs);
6554 doc->refs = NULL;
6555 }
6556 root = xmlDocGetRootElement(doc);
6557 ret = xmlValidateElement(ctxt, doc, root);
6558 ret &= xmlValidateDocumentFinal(ctxt, doc);
6559 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006560 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006561 return(ret);
6562}
6563
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006564static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006565xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6566 const xmlChar *name ATTRIBUTE_UNUSED) {
6567 if (cur == NULL)
6568 return;
6569 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6570 xmlChar *notation = cur->content;
6571
Daniel Veillard878eab02002-02-19 13:46:09 +00006572 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006573 int ret;
6574
6575 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6576 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006577 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006578 }
6579 }
6580 }
6581}
6582
6583static void
Owen Taylor3473f882001-02-23 17:55:21 +00006584xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006585 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006586 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006587 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006588 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006589
Owen Taylor3473f882001-02-23 17:55:21 +00006590 if (cur == NULL)
6591 return;
6592 switch (cur->atype) {
6593 case XML_ATTRIBUTE_CDATA:
6594 case XML_ATTRIBUTE_ID:
6595 case XML_ATTRIBUTE_IDREF :
6596 case XML_ATTRIBUTE_IDREFS:
6597 case XML_ATTRIBUTE_NMTOKEN:
6598 case XML_ATTRIBUTE_NMTOKENS:
6599 case XML_ATTRIBUTE_ENUMERATION:
6600 break;
6601 case XML_ATTRIBUTE_ENTITY:
6602 case XML_ATTRIBUTE_ENTITIES:
6603 case XML_ATTRIBUTE_NOTATION:
6604 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006605
6606 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6607 cur->atype, cur->defaultValue);
6608 if ((ret == 0) && (ctxt->valid == 1))
6609 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006610 }
6611 if (cur->tree != NULL) {
6612 xmlEnumerationPtr tree = cur->tree;
6613 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006614 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006615 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006616 if ((ret == 0) && (ctxt->valid == 1))
6617 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006618 tree = tree->next;
6619 }
6620 }
6621 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006622 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6623 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006624 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006625 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006626 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006627 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006628 return;
6629 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006630
6631 if (doc != NULL)
6632 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6633 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006634 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006635 if ((elem == NULL) && (cur->parent != NULL) &&
6636 (cur->parent->type == XML_DTD_NODE))
6637 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006638 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006639 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006640 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006641 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006642 return;
6643 }
6644 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006645 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006646 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006647 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006648 ctxt->valid = 0;
6649 }
6650 }
Owen Taylor3473f882001-02-23 17:55:21 +00006651}
6652
6653/**
6654 * xmlValidateDtdFinal:
6655 * @ctxt: the validation context
6656 * @doc: a document instance
6657 *
6658 * Does the final step for the dtds validation once all the
6659 * subsets have been parsed
6660 *
6661 * basically it does the following checks described by the XML Rec
6662 * - check that ENTITY and ENTITIES type attributes default or
6663 * possible values matches one of the defined entities.
6664 * - check that NOTATION type attributes default or
6665 * possible values matches one of the defined notations.
6666 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006667 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006668 */
6669
6670int
6671xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006672 xmlDtdPtr dtd;
6673 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006674 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006675
6676 if (doc == NULL) return(0);
6677 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6678 return(0);
6679 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006680 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006681 dtd = doc->intSubset;
6682 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6683 table = (xmlAttributeTablePtr) dtd->attributes;
6684 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006685 }
6686 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006687 entities = (xmlEntitiesTablePtr) dtd->entities;
6688 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6689 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006690 }
6691 dtd = doc->extSubset;
6692 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6693 table = (xmlAttributeTablePtr) dtd->attributes;
6694 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006695 }
6696 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006697 entities = (xmlEntitiesTablePtr) dtd->entities;
6698 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6699 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006700 }
6701 return(ctxt->valid);
6702}
6703
6704/**
6705 * xmlValidateDocument:
6706 * @ctxt: the validation context
6707 * @doc: a document instance
6708 *
6709 * Try to validate the document instance
6710 *
6711 * basically it does the all the checks described by the XML Rec
6712 * i.e. validates the internal and external subset (if present)
6713 * and validate the document tree.
6714 *
6715 * returns 1 if valid or 0 otherwise
6716 */
6717
6718int
6719xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6720 int ret;
6721 xmlNodePtr root;
6722
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006723 if (doc == NULL)
6724 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006725 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006726 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6727 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006728 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006729 }
Owen Taylor3473f882001-02-23 17:55:21 +00006730 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6731 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
William M. Brack8c22f9f2004-08-06 16:23:27 +00006732 xmlChar *sysID;
6733 if (doc->intSubset->SystemID != NULL) {
William M. Brackbebe7302004-08-05 06:46:47 +00006734 sysID = xmlBuildURI(doc->intSubset->SystemID,
6735 doc->URL);
William M. Brack8c22f9f2004-08-06 16:23:27 +00006736 if (sysID == NULL) {
6737 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6738 "Could not build URI for external subset \"%s\"\n",
6739 (const char *) doc->intSubset->SystemID);
6740 return 0;
6741 }
6742 } else
William M. Brackbebe7302004-08-05 06:46:47 +00006743 sysID = NULL;
William M. Brack8c22f9f2004-08-06 16:23:27 +00006744 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
William M. Brackbebe7302004-08-05 06:46:47 +00006745 (const xmlChar *)sysID);
William M. Brackbebe7302004-08-05 06:46:47 +00006746 if (sysID != NULL)
6747 xmlFree(sysID);
Owen Taylor3473f882001-02-23 17:55:21 +00006748 if (doc->extSubset == NULL) {
6749 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006750 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006751 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006752 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006753 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006754 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006755 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006756 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006757 }
6758 return(0);
6759 }
6760 }
6761
6762 if (doc->ids != NULL) {
6763 xmlFreeIDTable(doc->ids);
6764 doc->ids = NULL;
6765 }
6766 if (doc->refs != NULL) {
6767 xmlFreeRefTable(doc->refs);
6768 doc->refs = NULL;
6769 }
6770 ret = xmlValidateDtdFinal(ctxt, doc);
6771 if (!xmlValidateRoot(ctxt, doc)) return(0);
6772
6773 root = xmlDocGetRootElement(doc);
6774 ret &= xmlValidateElement(ctxt, doc, root);
6775 ret &= xmlValidateDocumentFinal(ctxt, doc);
6776 return(ret);
6777}
6778
Owen Taylor3473f882001-02-23 17:55:21 +00006779/************************************************************************
6780 * *
6781 * Routines for dynamic validation editing *
6782 * *
6783 ************************************************************************/
6784
6785/**
6786 * xmlValidGetPotentialChildren:
6787 * @ctree: an element content tree
Daniel Veillard7802ba52005-10-27 11:56:20 +00006788 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006789 * @len: a pointer to the number of element in the list
6790 * @max: the size of the array
6791 *
6792 * Build/extend a list of potential children allowed by the content tree
6793 *
6794 * returns the number of element in the list, or -1 in case of error.
6795 */
6796
6797int
Daniel Veillard7802ba52005-10-27 11:56:20 +00006798xmlValidGetPotentialChildren(xmlElementContent *ctree,
6799 const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006800 int *len, int max) {
6801 int i;
6802
Daniel Veillard7802ba52005-10-27 11:56:20 +00006803 if ((ctree == NULL) || (names == NULL) || (len == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006804 return(-1);
6805 if (*len >= max) return(*len);
6806
6807 switch (ctree->type) {
6808 case XML_ELEMENT_CONTENT_PCDATA:
6809 for (i = 0; i < *len;i++)
Daniel Veillard7802ba52005-10-27 11:56:20 +00006810 if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
6811 names[(*len)++] = BAD_CAST "#PCDATA";
Owen Taylor3473f882001-02-23 17:55:21 +00006812 break;
6813 case XML_ELEMENT_CONTENT_ELEMENT:
6814 for (i = 0; i < *len;i++)
Daniel Veillard7802ba52005-10-27 11:56:20 +00006815 if (xmlStrEqual(ctree->name, names[i])) return(*len);
6816 names[(*len)++] = ctree->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006817 break;
6818 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard7802ba52005-10-27 11:56:20 +00006819 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6820 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
Owen Taylor3473f882001-02-23 17:55:21 +00006821 break;
6822 case XML_ELEMENT_CONTENT_OR:
Daniel Veillard7802ba52005-10-27 11:56:20 +00006823 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6824 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
Owen Taylor3473f882001-02-23 17:55:21 +00006825 break;
6826 }
6827
6828 return(*len);
6829}
6830
William M. Brack9333cc22004-06-24 08:33:40 +00006831/*
6832 * Dummy function to suppress messages while we try out valid elements
6833 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00006834static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
William M. Brack9333cc22004-06-24 08:33:40 +00006835 const char *msg ATTRIBUTE_UNUSED, ...) {
6836 return;
6837}
6838
Owen Taylor3473f882001-02-23 17:55:21 +00006839/**
6840 * xmlValidGetValidElements:
6841 * @prev: an element to insert after
6842 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006843 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006844 * @max: the size of the array
6845 *
6846 * This function returns the list of authorized children to insert
6847 * within an existing tree while respecting the validity constraints
6848 * forced by the Dtd. The insertion point is defined using @prev and
6849 * @next in the following ways:
6850 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6851 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6852 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6853 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6854 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6855 *
6856 * pointers to the element names are inserted at the beginning of the array
6857 * and do not need to be freed.
6858 *
6859 * returns the number of element in the list, or -1 in case of error. If
6860 * the function returns the value @max the caller is invited to grow the
6861 * receiving array and retry.
6862 */
6863
6864int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006865xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006866 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006867 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006868 int nb_valid_elements = 0;
6869 const xmlChar *elements[256];
6870 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006871 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006872
6873 xmlNode *ref_node;
6874 xmlNode *parent;
6875 xmlNode *test_node;
6876
6877 xmlNode *prev_next;
6878 xmlNode *next_prev;
6879 xmlNode *parent_childs;
6880 xmlNode *parent_last;
6881
6882 xmlElement *element_desc;
6883
6884 if (prev == NULL && next == NULL)
6885 return(-1);
6886
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006887 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006888 if (max <= 0) return(-1);
6889
William M. Brack9333cc22004-06-24 08:33:40 +00006890 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6891 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6892
Owen Taylor3473f882001-02-23 17:55:21 +00006893 nb_valid_elements = 0;
6894 ref_node = prev ? prev : next;
6895 parent = ref_node->parent;
6896
6897 /*
6898 * Retrieves the parent element declaration
6899 */
6900 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6901 parent->name);
6902 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6903 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6904 parent->name);
6905 if (element_desc == NULL) return(-1);
6906
6907 /*
6908 * Do a backup of the current tree structure
6909 */
6910 prev_next = prev ? prev->next : NULL;
6911 next_prev = next ? next->prev : NULL;
6912 parent_childs = parent->children;
6913 parent_last = parent->last;
6914
6915 /*
6916 * Creates a dummy node and insert it into the tree
6917 */
Daniel Veillard95ddcd32004-10-26 21:53:55 +00006918 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006919 test_node->parent = parent;
6920 test_node->prev = prev;
6921 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006922 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006923
6924 if (prev) prev->next = test_node;
6925 else parent->children = test_node;
6926
6927 if (next) next->prev = test_node;
6928 else parent->last = test_node;
6929
6930 /*
6931 * Insert each potential child node and check if the parent is
6932 * still valid
6933 */
6934 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6935 elements, &nb_elements, 256);
6936
6937 for (i = 0;i < nb_elements;i++) {
6938 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006939 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006940 int j;
6941
6942 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006943 if (xmlStrEqual(elements[i], names[j])) break;
6944 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00006945 if (nb_valid_elements >= max) break;
6946 }
6947 }
6948
6949 /*
6950 * Restore the tree structure
6951 */
6952 if (prev) prev->next = prev_next;
6953 if (next) next->prev = next_prev;
6954 parent->children = parent_childs;
6955 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006956
6957 /*
6958 * Free up the dummy node
6959 */
6960 test_node->name = name;
6961 xmlFreeNode(test_node);
6962
Owen Taylor3473f882001-02-23 17:55:21 +00006963 return(nb_valid_elements);
6964}
Daniel Veillard4432df22003-09-28 18:58:27 +00006965#endif /* LIBXML_VALID_ENABLED */
6966
Daniel Veillard5d4644e2005-04-01 13:11:58 +00006967#define bottom_valid
6968#include "elfgcchack.h"