blob: a239e684cd1dacf34e39ac5e46181ebdad7c35e4 [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)) &&
2727 ((elem == NULL) || (!xmlStrEqual(elem->name, BAD_CAST "input")))))
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 Veillard37721922001-05-04 15:21:12 +00003001 return(NULL);
3002 }
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 Veillard37721922001-05-04 15:21:12 +00003008 return(NULL);
3009 }
3010 }
Daniel Veillard965983a2004-02-17 16:30:24 +00003011/* xmlListInsert(ref_list, ret); */
3012 xmlListAppend(ref_list, ret);
Daniel Veillard37721922001-05-04 15:21:12 +00003013 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003014}
3015
3016/**
3017 * xmlFreeRefTable:
3018 * @table: An ref table
3019 *
3020 * Deallocate the memory used by an Ref hash table.
3021 */
3022void
3023xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00003024 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00003025}
3026
3027/**
3028 * xmlIsRef:
3029 * @doc: the document
3030 * @elem: the element carrying the attribute
3031 * @attr: the attribute
3032 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003033 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00003034 * then this is simple, otherwise we use an heuristic: name Ref (upper
3035 * or lowercase).
3036 *
3037 * Returns 0 or 1 depending on the lookup result
3038 */
3039int
3040xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003041 if (attr == NULL)
3042 return(0);
3043 if (doc == NULL) {
3044 doc = attr->doc;
3045 if (doc == NULL) return(0);
3046 }
3047
Daniel Veillard37721922001-05-04 15:21:12 +00003048 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3049 return(0);
3050 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3051 /* TODO @@@ */
3052 return(0);
3053 } else {
3054 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00003055
Daniel Veillardce244ad2004-11-05 10:03:46 +00003056 if (elem == NULL) return(0);
Daniel Veillard37721922001-05-04 15:21:12 +00003057 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3058 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3059 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3060 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00003061
Daniel Veillard37721922001-05-04 15:21:12 +00003062 if ((attrDecl != NULL) &&
3063 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3064 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3065 return(1);
3066 }
3067 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003068}
3069
3070/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003071 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00003072 * @doc: the document
3073 * @attr: the attribute
3074 *
3075 * Remove the given attribute from the Ref table maintained internally.
3076 *
3077 * Returns -1 if the lookup failed and 0 otherwise
3078 */
3079int
3080xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00003081 xmlListPtr ref_list;
3082 xmlRefTablePtr table;
3083 xmlChar *ID;
3084 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00003085
Daniel Veillard37721922001-05-04 15:21:12 +00003086 if (doc == NULL) return(-1);
3087 if (attr == NULL) return(-1);
3088 table = (xmlRefTablePtr) doc->refs;
3089 if (table == NULL)
3090 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003091
Daniel Veillard37721922001-05-04 15:21:12 +00003092 if (attr == NULL)
3093 return(-1);
3094 ID = xmlNodeListGetString(doc, attr->children, 1);
3095 if (ID == NULL)
3096 return(-1);
3097 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00003098
Daniel Veillard37721922001-05-04 15:21:12 +00003099 if(ref_list == NULL) {
3100 xmlFree(ID);
3101 return (-1);
3102 }
3103 /* At this point, ref_list refers to a list of references which
3104 * have the same key as the supplied attr. Our list of references
3105 * is ordered by reference address and we don't have that information
3106 * here to use when removing. We'll have to walk the list and
3107 * check for a matching attribute, when we find one stop the walk
3108 * and remove the entry.
3109 * The list is ordered by reference, so that means we don't have the
3110 * key. Passing the list and the reference to the walker means we
3111 * will have enough data to be able to remove the entry.
3112 */
3113 target.l = ref_list;
3114 target.ap = attr;
3115
3116 /* Remove the supplied attr from our list */
3117 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00003118
Daniel Veillard37721922001-05-04 15:21:12 +00003119 /*If the list is empty then remove the list entry in the hash */
3120 if (xmlListEmpty(ref_list))
3121 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
3122 xmlFreeRefList);
3123 xmlFree(ID);
3124 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003125}
3126
3127/**
3128 * xmlGetRefs:
3129 * @doc: pointer to the document
3130 * @ID: the ID value
3131 *
3132 * Find the set of references for the supplied ID.
3133 *
3134 * Returns NULL if not found, otherwise node set for the ID.
3135 */
3136xmlListPtr
3137xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00003138 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00003139
Daniel Veillard37721922001-05-04 15:21:12 +00003140 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003141 return(NULL);
3142 }
Owen Taylor3473f882001-02-23 17:55:21 +00003143
Daniel Veillard37721922001-05-04 15:21:12 +00003144 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003145 return(NULL);
3146 }
Owen Taylor3473f882001-02-23 17:55:21 +00003147
Daniel Veillard37721922001-05-04 15:21:12 +00003148 table = (xmlRefTablePtr) doc->refs;
3149 if (table == NULL)
3150 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003151
Daniel Veillard37721922001-05-04 15:21:12 +00003152 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00003153}
3154
3155/************************************************************************
3156 * *
3157 * Routines for validity checking *
3158 * *
3159 ************************************************************************/
3160
3161/**
3162 * xmlGetDtdElementDesc:
3163 * @dtd: a pointer to the DtD to search
3164 * @name: the element name
3165 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003166 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003167 *
3168 * returns the xmlElementPtr if found or NULL
3169 */
3170
3171xmlElementPtr
3172xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3173 xmlElementTablePtr table;
3174 xmlElementPtr cur;
3175 xmlChar *uqname = NULL, *prefix = NULL;
3176
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00003177 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003178 if (dtd->elements == NULL)
3179 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003180 table = (xmlElementTablePtr) dtd->elements;
3181
3182 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003183 if (uqname != NULL)
3184 name = uqname;
3185 cur = xmlHashLookup2(table, name, prefix);
3186 if (prefix != NULL) xmlFree(prefix);
3187 if (uqname != NULL) xmlFree(uqname);
3188 return(cur);
3189}
3190/**
3191 * xmlGetDtdElementDesc2:
3192 * @dtd: a pointer to the DtD to search
3193 * @name: the element name
3194 * @create: create an empty description if not found
3195 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003196 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00003197 *
3198 * returns the xmlElementPtr if found or NULL
3199 */
3200
Daniel Veillard86fd5a72001-12-13 14:55:21 +00003201static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00003202xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3203 xmlElementTablePtr table;
3204 xmlElementPtr cur;
3205 xmlChar *uqname = NULL, *prefix = NULL;
3206
3207 if (dtd == NULL) return(NULL);
3208 if (dtd->elements == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003209 xmlDictPtr dict = NULL;
3210
3211 if (dtd->doc != NULL)
3212 dict = dtd->doc->dict;
3213
Daniel Veillarda10efa82001-04-18 13:09:01 +00003214 if (!create)
3215 return(NULL);
3216 /*
3217 * Create the Element table if needed.
3218 */
3219 table = (xmlElementTablePtr) dtd->elements;
3220 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003221 table = xmlHashCreateDict(0, dict);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003222 dtd->elements = (void *) table;
3223 }
3224 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003225 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003226 return(NULL);
3227 }
3228 }
3229 table = (xmlElementTablePtr) dtd->elements;
3230
3231 uqname = xmlSplitQName2(name, &prefix);
3232 if (uqname != NULL)
3233 name = uqname;
3234 cur = xmlHashLookup2(table, name, prefix);
3235 if ((cur == NULL) && (create)) {
3236 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3237 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003238 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003239 return(NULL);
3240 }
3241 memset(cur, 0, sizeof(xmlElement));
3242 cur->type = XML_ELEMENT_DECL;
3243
3244 /*
3245 * fill the structure.
3246 */
3247 cur->name = xmlStrdup(name);
3248 cur->prefix = xmlStrdup(prefix);
3249 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3250
3251 xmlHashAddEntry2(table, name, prefix, cur);
3252 }
3253 if (prefix != NULL) xmlFree(prefix);
3254 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003255 return(cur);
3256}
3257
3258/**
3259 * xmlGetDtdQElementDesc:
3260 * @dtd: a pointer to the DtD to search
3261 * @name: the element name
3262 * @prefix: the element namespace prefix
3263 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003264 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003265 *
3266 * returns the xmlElementPtr if found or NULL
3267 */
3268
Daniel Veillard48da9102001-08-07 01:10:10 +00003269xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003270xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3271 const xmlChar *prefix) {
3272 xmlElementTablePtr table;
3273
3274 if (dtd == NULL) return(NULL);
3275 if (dtd->elements == NULL) return(NULL);
3276 table = (xmlElementTablePtr) dtd->elements;
3277
3278 return(xmlHashLookup2(table, name, prefix));
3279}
3280
3281/**
3282 * xmlGetDtdAttrDesc:
3283 * @dtd: a pointer to the DtD to search
3284 * @elem: the element name
3285 * @name: the attribute name
3286 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003287 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003288 * this element.
3289 *
3290 * returns the xmlAttributePtr if found or NULL
3291 */
3292
3293xmlAttributePtr
3294xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3295 xmlAttributeTablePtr table;
3296 xmlAttributePtr cur;
3297 xmlChar *uqname = NULL, *prefix = NULL;
3298
3299 if (dtd == NULL) return(NULL);
3300 if (dtd->attributes == NULL) return(NULL);
3301
3302 table = (xmlAttributeTablePtr) dtd->attributes;
3303 if (table == NULL)
3304 return(NULL);
3305
3306 uqname = xmlSplitQName2(name, &prefix);
3307
3308 if (uqname != NULL) {
3309 cur = xmlHashLookup3(table, uqname, prefix, elem);
3310 if (prefix != NULL) xmlFree(prefix);
3311 if (uqname != NULL) xmlFree(uqname);
3312 } else
3313 cur = xmlHashLookup3(table, name, NULL, elem);
3314 return(cur);
3315}
3316
3317/**
3318 * xmlGetDtdQAttrDesc:
3319 * @dtd: a pointer to the DtD to search
3320 * @elem: the element name
3321 * @name: the attribute name
3322 * @prefix: the attribute namespace prefix
3323 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003324 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003325 * this element.
3326 *
3327 * returns the xmlAttributePtr if found or NULL
3328 */
3329
Daniel Veillard48da9102001-08-07 01:10:10 +00003330xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003331xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3332 const xmlChar *prefix) {
3333 xmlAttributeTablePtr table;
3334
3335 if (dtd == NULL) return(NULL);
3336 if (dtd->attributes == NULL) return(NULL);
3337 table = (xmlAttributeTablePtr) dtd->attributes;
3338
3339 return(xmlHashLookup3(table, name, prefix, elem));
3340}
3341
3342/**
3343 * xmlGetDtdNotationDesc:
3344 * @dtd: a pointer to the DtD to search
3345 * @name: the notation name
3346 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003347 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003348 *
3349 * returns the xmlNotationPtr if found or NULL
3350 */
3351
3352xmlNotationPtr
3353xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3354 xmlNotationTablePtr table;
3355
3356 if (dtd == NULL) return(NULL);
3357 if (dtd->notations == NULL) return(NULL);
3358 table = (xmlNotationTablePtr) dtd->notations;
3359
3360 return(xmlHashLookup(table, name));
3361}
3362
Daniel Veillardf54cd532004-02-25 11:52:31 +00003363#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003364/**
3365 * xmlValidateNotationUse:
3366 * @ctxt: the validation context
3367 * @doc: the document
3368 * @notationName: the notation name to check
3369 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003370 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003371 * - [ VC: Notation Declared ]
3372 *
3373 * returns 1 if valid or 0 otherwise
3374 */
3375
3376int
3377xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3378 const xmlChar *notationName) {
3379 xmlNotationPtr notaDecl;
3380 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3381
3382 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3383 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3384 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3385
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003386 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003387 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3388 "NOTATION %s is not declared\n",
3389 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003390 return(0);
3391 }
3392 return(1);
3393}
Daniel Veillardf54cd532004-02-25 11:52:31 +00003394#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003395
3396/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003397 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003398 * @doc: the document
3399 * @name: the element name
3400 *
3401 * Search in the DtDs whether an element accept Mixed content (or ANY)
3402 * basically if it is supposed to accept text childs
3403 *
3404 * returns 0 if no, 1 if yes, and -1 if no element description is available
3405 */
3406
3407int
3408xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3409 xmlElementPtr elemDecl;
3410
3411 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3412
3413 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3414 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3415 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3416 if (elemDecl == NULL) return(-1);
3417 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003418 case XML_ELEMENT_TYPE_UNDEFINED:
3419 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003420 case XML_ELEMENT_TYPE_ELEMENT:
3421 return(0);
3422 case XML_ELEMENT_TYPE_EMPTY:
3423 /*
3424 * return 1 for EMPTY since we want VC error to pop up
3425 * on <empty> </empty> for example
3426 */
3427 case XML_ELEMENT_TYPE_ANY:
3428 case XML_ELEMENT_TYPE_MIXED:
3429 return(1);
3430 }
3431 return(1);
3432}
3433
Daniel Veillard4432df22003-09-28 18:58:27 +00003434#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003435/**
3436 * xmlValidateNameValue:
3437 * @value: an Name value
3438 *
3439 * Validate that the given value match Name production
3440 *
3441 * returns 1 if valid or 0 otherwise
3442 */
3443
Daniel Veillard9b731d72002-04-14 12:56:08 +00003444int
Owen Taylor3473f882001-02-23 17:55:21 +00003445xmlValidateNameValue(const xmlChar *value) {
3446 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003447 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003448
3449 if (value == NULL) return(0);
3450 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003451 val = xmlStringCurrentChar(NULL, cur, &len);
3452 cur += len;
3453 if (!IS_LETTER(val) && (val != '_') &&
3454 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003455 return(0);
3456 }
3457
Daniel Veillardd8224e02002-01-13 15:43:22 +00003458 val = xmlStringCurrentChar(NULL, cur, &len);
3459 cur += len;
3460 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3461 (val == '.') || (val == '-') ||
3462 (val == '_') || (val == ':') ||
3463 (IS_COMBINING(val)) ||
3464 (IS_EXTENDER(val))) {
3465 val = xmlStringCurrentChar(NULL, cur, &len);
3466 cur += len;
3467 }
Owen Taylor3473f882001-02-23 17:55:21 +00003468
Daniel Veillardd8224e02002-01-13 15:43:22 +00003469 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003470
3471 return(1);
3472}
3473
3474/**
3475 * xmlValidateNamesValue:
3476 * @value: an Names value
3477 *
3478 * Validate that the given value match Names production
3479 *
3480 * returns 1 if valid or 0 otherwise
3481 */
3482
Daniel Veillard9b731d72002-04-14 12:56:08 +00003483int
Owen Taylor3473f882001-02-23 17:55:21 +00003484xmlValidateNamesValue(const xmlChar *value) {
3485 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003486 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003487
3488 if (value == NULL) return(0);
3489 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003490 val = xmlStringCurrentChar(NULL, cur, &len);
3491 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003492
Daniel Veillardd8224e02002-01-13 15:43:22 +00003493 if (!IS_LETTER(val) && (val != '_') &&
3494 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003495 return(0);
3496 }
3497
Daniel Veillardd8224e02002-01-13 15:43:22 +00003498 val = xmlStringCurrentChar(NULL, cur, &len);
3499 cur += len;
3500 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3501 (val == '.') || (val == '-') ||
3502 (val == '_') || (val == ':') ||
3503 (IS_COMBINING(val)) ||
3504 (IS_EXTENDER(val))) {
3505 val = xmlStringCurrentChar(NULL, cur, &len);
3506 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003507 }
3508
Daniel Veillard807b4de2004-09-26 14:42:56 +00003509 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3510 while (val == 0x20) {
3511 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003512 val = xmlStringCurrentChar(NULL, cur, &len);
3513 cur += len;
3514 }
3515
3516 if (!IS_LETTER(val) && (val != '_') &&
3517 (val != ':')) {
3518 return(0);
3519 }
3520 val = xmlStringCurrentChar(NULL, cur, &len);
3521 cur += len;
3522
3523 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3524 (val == '.') || (val == '-') ||
3525 (val == '_') || (val == ':') ||
3526 (IS_COMBINING(val)) ||
3527 (IS_EXTENDER(val))) {
3528 val = xmlStringCurrentChar(NULL, cur, &len);
3529 cur += len;
3530 }
3531 }
3532
3533 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003534
3535 return(1);
3536}
3537
3538/**
3539 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003540 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003541 *
3542 * Validate that the given value match Nmtoken production
3543 *
3544 * [ VC: Name Token ]
3545 *
3546 * returns 1 if valid or 0 otherwise
3547 */
3548
Daniel Veillard9b731d72002-04-14 12:56:08 +00003549int
Owen Taylor3473f882001-02-23 17:55:21 +00003550xmlValidateNmtokenValue(const xmlChar *value) {
3551 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003552 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003553
3554 if (value == NULL) return(0);
3555 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003556 val = xmlStringCurrentChar(NULL, cur, &len);
3557 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003558
Daniel Veillardd8224e02002-01-13 15:43:22 +00003559 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3560 (val != '.') && (val != '-') &&
3561 (val != '_') && (val != ':') &&
3562 (!IS_COMBINING(val)) &&
3563 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003564 return(0);
3565
Daniel Veillardd8224e02002-01-13 15:43:22 +00003566 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3567 (val == '.') || (val == '-') ||
3568 (val == '_') || (val == ':') ||
3569 (IS_COMBINING(val)) ||
3570 (IS_EXTENDER(val))) {
3571 val = xmlStringCurrentChar(NULL, cur, &len);
3572 cur += len;
3573 }
Owen Taylor3473f882001-02-23 17:55:21 +00003574
Daniel Veillardd8224e02002-01-13 15:43:22 +00003575 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003576
3577 return(1);
3578}
3579
3580/**
3581 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003582 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003583 *
3584 * Validate that the given value match Nmtokens production
3585 *
3586 * [ VC: Name Token ]
3587 *
3588 * returns 1 if valid or 0 otherwise
3589 */
3590
Daniel Veillard9b731d72002-04-14 12:56:08 +00003591int
Owen Taylor3473f882001-02-23 17:55:21 +00003592xmlValidateNmtokensValue(const xmlChar *value) {
3593 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003594 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003595
3596 if (value == NULL) return(0);
3597 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003598 val = xmlStringCurrentChar(NULL, cur, &len);
3599 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003600
Daniel Veillardd8224e02002-01-13 15:43:22 +00003601 while (IS_BLANK(val)) {
3602 val = xmlStringCurrentChar(NULL, cur, &len);
3603 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003604 }
3605
Daniel Veillardd8224e02002-01-13 15:43:22 +00003606 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3607 (val != '.') && (val != '-') &&
3608 (val != '_') && (val != ':') &&
3609 (!IS_COMBINING(val)) &&
3610 (!IS_EXTENDER(val)))
3611 return(0);
3612
3613 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3614 (val == '.') || (val == '-') ||
3615 (val == '_') || (val == ':') ||
3616 (IS_COMBINING(val)) ||
3617 (IS_EXTENDER(val))) {
3618 val = xmlStringCurrentChar(NULL, cur, &len);
3619 cur += len;
3620 }
3621
Daniel Veillard807b4de2004-09-26 14:42:56 +00003622 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3623 while (val == 0x20) {
3624 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003625 val = xmlStringCurrentChar(NULL, cur, &len);
3626 cur += len;
3627 }
3628 if (val == 0) return(1);
3629
3630 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3631 (val != '.') && (val != '-') &&
3632 (val != '_') && (val != ':') &&
3633 (!IS_COMBINING(val)) &&
3634 (!IS_EXTENDER(val)))
3635 return(0);
3636
3637 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3638 (val == '.') || (val == '-') ||
3639 (val == '_') || (val == ':') ||
3640 (IS_COMBINING(val)) ||
3641 (IS_EXTENDER(val))) {
3642 val = xmlStringCurrentChar(NULL, cur, &len);
3643 cur += len;
3644 }
3645 }
3646
3647 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003648
3649 return(1);
3650}
3651
3652/**
3653 * xmlValidateNotationDecl:
3654 * @ctxt: the validation context
3655 * @doc: a document instance
3656 * @nota: a notation definition
3657 *
3658 * Try to validate a single notation definition
3659 * basically it does the following checks as described by the
3660 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003661 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003662 * But this function get called anyway ...
3663 *
3664 * returns 1 if valid or 0 otherwise
3665 */
3666
3667int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003668xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3669 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003670 int ret = 1;
3671
3672 return(ret);
3673}
3674
3675/**
3676 * xmlValidateAttributeValue:
3677 * @type: an attribute type
3678 * @value: an attribute value
3679 *
3680 * Validate that the given attribute value match the proper production
3681 *
3682 * [ VC: ID ]
3683 * Values of type ID must match the Name production....
3684 *
3685 * [ VC: IDREF ]
3686 * Values of type IDREF must match the Name production, and values
3687 * of type IDREFS must match Names ...
3688 *
3689 * [ VC: Entity Name ]
3690 * Values of type ENTITY must match the Name production, values
3691 * of type ENTITIES must match Names ...
3692 *
3693 * [ VC: Name Token ]
3694 * Values of type NMTOKEN must match the Nmtoken production; values
3695 * of type NMTOKENS must match Nmtokens.
3696 *
3697 * returns 1 if valid or 0 otherwise
3698 */
3699
3700int
3701xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3702 switch (type) {
3703 case XML_ATTRIBUTE_ENTITIES:
3704 case XML_ATTRIBUTE_IDREFS:
3705 return(xmlValidateNamesValue(value));
3706 case XML_ATTRIBUTE_ENTITY:
3707 case XML_ATTRIBUTE_IDREF:
3708 case XML_ATTRIBUTE_ID:
3709 case XML_ATTRIBUTE_NOTATION:
3710 return(xmlValidateNameValue(value));
3711 case XML_ATTRIBUTE_NMTOKENS:
3712 case XML_ATTRIBUTE_ENUMERATION:
3713 return(xmlValidateNmtokensValue(value));
3714 case XML_ATTRIBUTE_NMTOKEN:
3715 return(xmlValidateNmtokenValue(value));
3716 case XML_ATTRIBUTE_CDATA:
3717 break;
3718 }
3719 return(1);
3720}
3721
3722/**
3723 * xmlValidateAttributeValue2:
3724 * @ctxt: the validation context
3725 * @doc: the document
3726 * @name: the attribute name (used for error reporting only)
3727 * @type: the attribute type
3728 * @value: the attribute value
3729 *
3730 * Validate that the given attribute value match a given type.
3731 * This typically cannot be done before having finished parsing
3732 * the subsets.
3733 *
3734 * [ VC: IDREF ]
3735 * Values of type IDREF must match one of the declared IDs
3736 * Values of type IDREFS must match a sequence of the declared IDs
3737 * each Name must match the value of an ID attribute on some element
3738 * in the XML document; i.e. IDREF values must match the value of
3739 * some ID attribute
3740 *
3741 * [ VC: Entity Name ]
3742 * Values of type ENTITY must match one declared entity
3743 * Values of type ENTITIES must match a sequence of declared entities
3744 *
3745 * [ VC: Notation Attributes ]
3746 * all notation names in the declaration must be declared.
3747 *
3748 * returns 1 if valid or 0 otherwise
3749 */
3750
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003751static int
Owen Taylor3473f882001-02-23 17:55:21 +00003752xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3753 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3754 int ret = 1;
3755 switch (type) {
3756 case XML_ATTRIBUTE_IDREFS:
3757 case XML_ATTRIBUTE_IDREF:
3758 case XML_ATTRIBUTE_ID:
3759 case XML_ATTRIBUTE_NMTOKENS:
3760 case XML_ATTRIBUTE_ENUMERATION:
3761 case XML_ATTRIBUTE_NMTOKEN:
3762 case XML_ATTRIBUTE_CDATA:
3763 break;
3764 case XML_ATTRIBUTE_ENTITY: {
3765 xmlEntityPtr ent;
3766
3767 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003768 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003769 if ((ent == NULL) && (doc->standalone == 1)) {
3770 doc->standalone = 0;
3771 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003772 }
Owen Taylor3473f882001-02-23 17:55:21 +00003773 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003774 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3775 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003776 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003777 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003778 ret = 0;
3779 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003780 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3781 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003782 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003783 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003784 ret = 0;
3785 }
3786 break;
3787 }
3788 case XML_ATTRIBUTE_ENTITIES: {
3789 xmlChar *dup, *nam = NULL, *cur, save;
3790 xmlEntityPtr ent;
3791
3792 dup = xmlStrdup(value);
3793 if (dup == NULL)
3794 return(0);
3795 cur = dup;
3796 while (*cur != 0) {
3797 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003798 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003799 save = *cur;
3800 *cur = 0;
3801 ent = xmlGetDocEntity(doc, nam);
3802 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003803 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3804 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003805 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003806 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003807 ret = 0;
3808 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003809 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3810 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003811 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003812 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003813 ret = 0;
3814 }
3815 if (save == 0)
3816 break;
3817 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003818 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003819 }
3820 xmlFree(dup);
3821 break;
3822 }
3823 case XML_ATTRIBUTE_NOTATION: {
3824 xmlNotationPtr nota;
3825
3826 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3827 if ((nota == NULL) && (doc->extSubset != NULL))
3828 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3829
3830 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003831 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3832 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003833 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003834 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003835 ret = 0;
3836 }
3837 break;
3838 }
3839 }
3840 return(ret);
3841}
3842
3843/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003844 * xmlValidCtxtNormalizeAttributeValue:
3845 * @ctxt: the validation context
3846 * @doc: the document
3847 * @elem: the parent
3848 * @name: the attribute name
3849 * @value: the attribute value
3850 * @ctxt: the validation context or NULL
3851 *
3852 * Does the validation related extra step of the normalization of attribute
3853 * values:
3854 *
3855 * If the declared value is not CDATA, then the XML processor must further
3856 * process the normalized attribute value by discarding any leading and
3857 * trailing space (#x20) characters, and by replacing sequences of space
3858 * (#x20) characters by single space (#x20) character.
3859 *
3860 * Also check VC: Standalone Document Declaration in P32, and update
3861 * ctxt->valid accordingly
3862 *
3863 * returns a new normalized string if normalization is needed, NULL otherwise
3864 * the caller must free the returned value.
3865 */
3866
3867xmlChar *
3868xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3869 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3870 xmlChar *ret, *dst;
3871 const xmlChar *src;
3872 xmlAttributePtr attrDecl = NULL;
3873 int extsubset = 0;
3874
3875 if (doc == NULL) return(NULL);
3876 if (elem == NULL) return(NULL);
3877 if (name == NULL) return(NULL);
3878 if (value == NULL) return(NULL);
3879
3880 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003881 xmlChar fn[50];
3882 xmlChar *fullname;
3883
3884 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3885 if (fullname == NULL)
Daniel Veillard24505b02005-07-28 23:49:35 +00003886 return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00003887 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003888 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003889 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003890 if (attrDecl != NULL)
3891 extsubset = 1;
3892 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003893 if ((fullname != fn) && (fullname != elem->name))
3894 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003895 }
3896 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3897 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3898 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3899 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3900 if (attrDecl != NULL)
3901 extsubset = 1;
3902 }
3903
3904 if (attrDecl == NULL)
3905 return(NULL);
3906 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3907 return(NULL);
3908
3909 ret = xmlStrdup(value);
3910 if (ret == NULL)
3911 return(NULL);
3912 src = value;
3913 dst = ret;
3914 while (*src == 0x20) src++;
3915 while (*src != 0) {
3916 if (*src == 0x20) {
3917 while (*src == 0x20) src++;
3918 if (*src != 0)
3919 *dst++ = 0x20;
3920 } else {
3921 *dst++ = *src++;
3922 }
3923 }
3924 *dst = 0;
3925 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003926 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003927"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003928 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003929 ctxt->valid = 0;
3930 }
3931 return(ret);
3932}
3933
3934/**
Owen Taylor3473f882001-02-23 17:55:21 +00003935 * xmlValidNormalizeAttributeValue:
3936 * @doc: the document
3937 * @elem: the parent
3938 * @name: the attribute name
3939 * @value: the attribute value
3940 *
3941 * Does the validation related extra step of the normalization of attribute
3942 * values:
3943 *
3944 * If the declared value is not CDATA, then the XML processor must further
3945 * process the normalized attribute value by discarding any leading and
3946 * trailing space (#x20) characters, and by replacing sequences of space
3947 * (#x20) characters by single space (#x20) character.
3948 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003949 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003950 * the caller must free the returned value.
3951 */
3952
3953xmlChar *
3954xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3955 const xmlChar *name, const xmlChar *value) {
3956 xmlChar *ret, *dst;
3957 const xmlChar *src;
3958 xmlAttributePtr attrDecl = NULL;
3959
3960 if (doc == NULL) return(NULL);
3961 if (elem == NULL) return(NULL);
3962 if (name == NULL) return(NULL);
3963 if (value == NULL) return(NULL);
3964
3965 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003966 xmlChar fn[50];
3967 xmlChar *fullname;
3968
3969 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3970 if (fullname == NULL)
Daniel Veillard24505b02005-07-28 23:49:35 +00003971 return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00003972 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003973 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003974 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3975 if ((fullname != fn) && (fullname != elem->name))
3976 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003977 }
3978 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3979 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3980 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3981
3982 if (attrDecl == NULL)
3983 return(NULL);
3984 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3985 return(NULL);
3986
3987 ret = xmlStrdup(value);
3988 if (ret == NULL)
3989 return(NULL);
3990 src = value;
3991 dst = ret;
3992 while (*src == 0x20) src++;
3993 while (*src != 0) {
3994 if (*src == 0x20) {
3995 while (*src == 0x20) src++;
3996 if (*src != 0)
3997 *dst++ = 0x20;
3998 } else {
3999 *dst++ = *src++;
4000 }
4001 }
4002 *dst = 0;
4003 return(ret);
4004}
4005
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004006static void
Owen Taylor3473f882001-02-23 17:55:21 +00004007xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00004008 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00004009 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4010}
4011
4012/**
4013 * xmlValidateAttributeDecl:
4014 * @ctxt: the validation context
4015 * @doc: a document instance
4016 * @attr: an attribute definition
4017 *
4018 * Try to validate a single attribute definition
4019 * basically it does the following checks as described by the
4020 * XML-1.0 recommendation:
4021 * - [ VC: Attribute Default Legal ]
4022 * - [ VC: Enumeration ]
4023 * - [ VC: ID Attribute Default ]
4024 *
4025 * The ID/IDREF uniqueness and matching are done separately
4026 *
4027 * returns 1 if valid or 0 otherwise
4028 */
4029
4030int
4031xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4032 xmlAttributePtr attr) {
4033 int ret = 1;
4034 int val;
4035 CHECK_DTD;
4036 if(attr == NULL) return(1);
4037
4038 /* Attribute Default Legal */
4039 /* Enumeration */
4040 if (attr->defaultValue != NULL) {
4041 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
4042 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004043 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004044 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004045 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004046 }
4047 ret &= val;
4048 }
4049
4050 /* ID Attribute Default */
4051 if ((attr->atype == XML_ATTRIBUTE_ID)&&
4052 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4053 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004054 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004055 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004056 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004057 ret = 0;
4058 }
4059
4060 /* One ID per Element Type */
4061 if (attr->atype == XML_ATTRIBUTE_ID) {
4062 int nbId;
4063
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004064 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00004065 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4066 attr->elem);
4067 if (elem != NULL) {
Daniel Veillarddbee0f12005-06-27 13:42:57 +00004068 nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00004069 } else {
4070 xmlAttributeTablePtr table;
4071
4072 /*
4073 * The attribute may be declared in the internal subset and the
4074 * element in the external subset.
4075 */
4076 nbId = 0;
Daniel Veillard11ce4002006-03-10 00:36:23 +00004077 if (doc->intSubset != NULL) {
4078 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4079 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
4080 xmlValidateAttributeIdCallback, &nbId);
4081 }
Owen Taylor3473f882001-02-23 17:55:21 +00004082 }
4083 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004084
4085 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004086 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4087 attr->elem, nbId, attr->name);
4088 } else if (doc->extSubset != NULL) {
4089 int extId = 0;
4090 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4091 if (elem != NULL) {
Daniel Veillarddbee0f12005-06-27 13:42:57 +00004092 extId = xmlScanIDAttributeDecl(NULL, elem, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00004093 }
4094 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004095 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004096 "Element %s has %d ID attribute defined in the external subset : %s\n",
4097 attr->elem, extId, attr->name);
4098 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004099 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004100"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004101 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004102 }
4103 }
4104 }
4105
4106 /* Validity Constraint: Enumeration */
4107 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4108 xmlEnumerationPtr tree = attr->tree;
4109 while (tree != NULL) {
4110 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4111 tree = tree->next;
4112 }
4113 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004114 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004115"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004116 attr->defaultValue, attr->name, attr->elem);
4117 ret = 0;
4118 }
4119 }
4120
4121 return(ret);
4122}
4123
4124/**
4125 * xmlValidateElementDecl:
4126 * @ctxt: the validation context
4127 * @doc: a document instance
4128 * @elem: an element definition
4129 *
4130 * Try to validate a single element definition
4131 * basically it does the following checks as described by the
4132 * XML-1.0 recommendation:
4133 * - [ VC: One ID per Element Type ]
4134 * - [ VC: No Duplicate Types ]
4135 * - [ VC: Unique Element Type Declaration ]
4136 *
4137 * returns 1 if valid or 0 otherwise
4138 */
4139
4140int
4141xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4142 xmlElementPtr elem) {
4143 int ret = 1;
4144 xmlElementPtr tst;
4145
4146 CHECK_DTD;
4147
4148 if (elem == NULL) return(1);
4149
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004150#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00004151#ifdef LIBXML_REGEXP_ENABLED
4152 /* Build the regexp associated to the content model */
4153 ret = xmlValidBuildContentModel(ctxt, elem);
4154#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004155#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00004156
Owen Taylor3473f882001-02-23 17:55:21 +00004157 /* No Duplicate Types */
4158 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4159 xmlElementContentPtr cur, next;
4160 const xmlChar *name;
4161
4162 cur = elem->content;
4163 while (cur != NULL) {
4164 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4165 if (cur->c1 == NULL) break;
4166 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4167 name = cur->c1->name;
4168 next = cur->c2;
4169 while (next != NULL) {
4170 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00004171 if ((xmlStrEqual(next->name, name)) &&
4172 (xmlStrEqual(next->prefix, cur->prefix))) {
4173 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004174 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00004175 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004176 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004177 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004178 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004179 "Definition of %s has duplicate references of %s:%s\n",
4180 elem->name, cur->prefix, name);
4181 }
Owen Taylor3473f882001-02-23 17:55:21 +00004182 ret = 0;
4183 }
4184 break;
4185 }
4186 if (next->c1 == NULL) break;
4187 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00004188 if ((xmlStrEqual(next->c1->name, name)) &&
4189 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
4190 if (cur->prefix == NULL) {
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 to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004193 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004194 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004195 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004196 "Definition of %s has duplicate references to %s:%s\n",
4197 elem->name, cur->prefix, name);
4198 }
Owen Taylor3473f882001-02-23 17:55:21 +00004199 ret = 0;
4200 }
4201 next = next->c2;
4202 }
4203 }
4204 cur = cur->c2;
4205 }
4206 }
4207
4208 /* VC: Unique Element Type Declaration */
4209 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004210 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004211 ((tst->prefix == elem->prefix) ||
4212 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004213 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004214 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4215 "Redefinition of element %s\n",
4216 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004217 ret = 0;
4218 }
4219 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004220 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004221 ((tst->prefix == elem->prefix) ||
4222 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004223 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004224 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4225 "Redefinition of element %s\n",
4226 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004227 ret = 0;
4228 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004229 /* One ID per Element Type
4230 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004231 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4232 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004233 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004234 return(ret);
4235}
4236
4237/**
4238 * xmlValidateOneAttribute:
4239 * @ctxt: the validation context
4240 * @doc: a document instance
4241 * @elem: an element instance
4242 * @attr: an attribute instance
4243 * @value: the attribute value (without entities processing)
4244 *
4245 * Try to validate a single attribute for an element
4246 * basically it does the following checks as described by the
4247 * XML-1.0 recommendation:
4248 * - [ VC: Attribute Value Type ]
4249 * - [ VC: Fixed Attribute Default ]
4250 * - [ VC: Entity Name ]
4251 * - [ VC: Name Token ]
4252 * - [ VC: ID ]
4253 * - [ VC: IDREF ]
4254 * - [ VC: Entity Name ]
4255 * - [ VC: Notation Attributes ]
4256 *
4257 * The ID/IDREF uniqueness and matching are done separately
4258 *
4259 * returns 1 if valid or 0 otherwise
4260 */
4261
4262int
4263xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004264 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4265{
Owen Taylor3473f882001-02-23 17:55:21 +00004266 xmlAttributePtr attrDecl = NULL;
4267 int val;
4268 int ret = 1;
4269
4270 CHECK_DTD;
4271 if ((elem == NULL) || (elem->name == NULL)) return(0);
4272 if ((attr == NULL) || (attr->name == NULL)) return(0);
4273
4274 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004275 xmlChar fn[50];
4276 xmlChar *fullname;
4277
4278 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4279 if (fullname == NULL)
4280 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004281 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004282 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004283 attr->name, attr->ns->prefix);
4284 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004285 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004286 attr->name, attr->ns->prefix);
4287 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004288 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004289 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4290 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004291 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004292 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004293 if ((fullname != fn) && (fullname != elem->name))
4294 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004295 }
4296 if (attrDecl == NULL) {
4297 if (attr->ns != NULL) {
4298 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4299 attr->name, attr->ns->prefix);
4300 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4301 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4302 attr->name, attr->ns->prefix);
4303 } else {
4304 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4305 elem->name, attr->name);
4306 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4307 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4308 elem->name, attr->name);
4309 }
4310 }
4311
4312
4313 /* Validity Constraint: Attribute Value Type */
4314 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004315 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004316 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004317 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004318 return(0);
4319 }
4320 attr->atype = attrDecl->atype;
4321
4322 val = xmlValidateAttributeValue(attrDecl->atype, value);
4323 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004324 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004325 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004326 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004327 ret = 0;
4328 }
4329
4330 /* Validity constraint: Fixed Attribute Default */
4331 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4332 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004333 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004334 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004335 attr->name, elem->name, attrDecl->defaultValue);
4336 ret = 0;
4337 }
4338 }
4339
4340 /* Validity Constraint: ID uniqueness */
4341 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4342 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4343 ret = 0;
4344 }
4345
4346 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4347 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4348 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4349 ret = 0;
4350 }
4351
4352 /* Validity Constraint: Notation Attributes */
4353 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4354 xmlEnumerationPtr tree = attrDecl->tree;
4355 xmlNotationPtr nota;
4356
4357 /* First check that the given NOTATION was declared */
4358 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4359 if (nota == NULL)
4360 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4361
4362 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004363 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004364 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004365 value, attr->name, elem->name);
4366 ret = 0;
4367 }
4368
4369 /* Second, verify that it's among the list */
4370 while (tree != NULL) {
4371 if (xmlStrEqual(tree->name, value)) break;
4372 tree = tree->next;
4373 }
4374 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004375 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004376"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004377 value, attr->name, elem->name);
4378 ret = 0;
4379 }
4380 }
4381
4382 /* Validity Constraint: Enumeration */
4383 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4384 xmlEnumerationPtr tree = attrDecl->tree;
4385 while (tree != NULL) {
4386 if (xmlStrEqual(tree->name, value)) break;
4387 tree = tree->next;
4388 }
4389 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004390 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004391 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004392 value, attr->name, elem->name);
4393 ret = 0;
4394 }
4395 }
4396
4397 /* Fixed Attribute Default */
4398 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4399 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004400 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004401 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004402 attr->name, elem->name, attrDecl->defaultValue);
4403 ret = 0;
4404 }
4405
4406 /* Extra check for the attribute value */
4407 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4408 attrDecl->atype, value);
4409
4410 return(ret);
4411}
4412
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004413/**
4414 * xmlValidateOneNamespace:
4415 * @ctxt: the validation context
4416 * @doc: a document instance
4417 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004418 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004419 * @ns: an namespace declaration instance
4420 * @value: the attribute value (without entities processing)
4421 *
4422 * Try to validate a single namespace declaration for an element
4423 * basically it does the following checks as described by the
4424 * XML-1.0 recommendation:
4425 * - [ VC: Attribute Value Type ]
4426 * - [ VC: Fixed Attribute Default ]
4427 * - [ VC: Entity Name ]
4428 * - [ VC: Name Token ]
4429 * - [ VC: ID ]
4430 * - [ VC: IDREF ]
4431 * - [ VC: Entity Name ]
4432 * - [ VC: Notation Attributes ]
4433 *
4434 * The ID/IDREF uniqueness and matching are done separately
4435 *
4436 * returns 1 if valid or 0 otherwise
4437 */
4438
4439int
4440xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4441xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4442 /* xmlElementPtr elemDecl; */
4443 xmlAttributePtr attrDecl = NULL;
4444 int val;
4445 int ret = 1;
4446
4447 CHECK_DTD;
4448 if ((elem == NULL) || (elem->name == NULL)) return(0);
4449 if ((ns == NULL) || (ns->href == NULL)) return(0);
4450
4451 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004452 xmlChar fn[50];
4453 xmlChar *fullname;
4454
4455 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4456 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004457 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004458 return(0);
4459 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004460 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004461 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004462 ns->prefix, BAD_CAST "xmlns");
4463 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004464 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004465 ns->prefix, BAD_CAST "xmlns");
4466 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004467 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004468 BAD_CAST "xmlns");
4469 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004470 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004471 BAD_CAST "xmlns");
4472 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004473 if ((fullname != fn) && (fullname != elem->name))
4474 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004475 }
4476 if (attrDecl == NULL) {
4477 if (ns->prefix != NULL) {
4478 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4479 ns->prefix, BAD_CAST "xmlns");
4480 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4481 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4482 ns->prefix, BAD_CAST "xmlns");
4483 } else {
4484 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4485 elem->name, BAD_CAST "xmlns");
4486 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4487 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4488 elem->name, BAD_CAST "xmlns");
4489 }
4490 }
4491
4492
4493 /* Validity Constraint: Attribute Value Type */
4494 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004495 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004496 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004497 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004498 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004499 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004500 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004501 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004502 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004503 }
4504 return(0);
4505 }
4506
4507 val = xmlValidateAttributeValue(attrDecl->atype, value);
4508 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004509 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004510 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004511 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004512 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004513 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004514 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004515 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004516 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004517 }
4518 ret = 0;
4519 }
4520
4521 /* Validity constraint: Fixed Attribute Default */
4522 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4523 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004524 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004525 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004526 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4527 ns->prefix, elem->name, attrDecl->defaultValue);
4528 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004529 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004530 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004531 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004532 }
4533 ret = 0;
4534 }
4535 }
4536
4537 /* Validity Constraint: ID uniqueness */
4538 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4539 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4540 ret = 0;
4541 }
4542
4543 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4544 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4545 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4546 ret = 0;
4547 }
4548
4549 /* Validity Constraint: Notation Attributes */
4550 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4551 xmlEnumerationPtr tree = attrDecl->tree;
4552 xmlNotationPtr nota;
4553
4554 /* First check that the given NOTATION was declared */
4555 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4556 if (nota == NULL)
4557 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4558
4559 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004560 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004561 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004562 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4563 value, ns->prefix, elem->name);
4564 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004565 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004566 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004567 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004568 }
4569 ret = 0;
4570 }
4571
4572 /* Second, verify that it's among the list */
4573 while (tree != NULL) {
4574 if (xmlStrEqual(tree->name, value)) break;
4575 tree = tree->next;
4576 }
4577 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004578 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004579 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004580"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4581 value, ns->prefix, elem->name);
4582 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004583 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004584"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004585 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004586 }
4587 ret = 0;
4588 }
4589 }
4590
4591 /* Validity Constraint: Enumeration */
4592 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4593 xmlEnumerationPtr tree = attrDecl->tree;
4594 while (tree != NULL) {
4595 if (xmlStrEqual(tree->name, value)) break;
4596 tree = tree->next;
4597 }
4598 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004599 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004600 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004601"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4602 value, ns->prefix, elem->name);
4603 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004604 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004605"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004606 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004607 }
4608 ret = 0;
4609 }
4610 }
4611
4612 /* Fixed Attribute Default */
4613 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4614 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004615 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004616 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004617 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4618 ns->prefix, elem->name, attrDecl->defaultValue);
4619 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004620 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004621 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004622 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004623 }
4624 ret = 0;
4625 }
4626
4627 /* Extra check for the attribute value */
4628 if (ns->prefix != NULL) {
4629 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4630 attrDecl->atype, value);
4631 } else {
4632 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4633 attrDecl->atype, value);
4634 }
4635
4636 return(ret);
4637}
4638
Daniel Veillard118aed72002-09-24 14:13:13 +00004639#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004640/**
4641 * xmlValidateSkipIgnorable:
4642 * @ctxt: the validation context
4643 * @child: the child list
4644 *
4645 * Skip ignorable elements w.r.t. the validation process
4646 *
4647 * returns the first element to consider for validation of the content model
4648 */
4649
4650static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004651xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004652 while (child != NULL) {
4653 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004654 /* These things are ignored (skipped) during validation. */
4655 case XML_PI_NODE:
4656 case XML_COMMENT_NODE:
4657 case XML_XINCLUDE_START:
4658 case XML_XINCLUDE_END:
4659 child = child->next;
4660 break;
4661 case XML_TEXT_NODE:
4662 if (xmlIsBlankNode(child))
4663 child = child->next;
4664 else
4665 return(child);
4666 break;
4667 /* keep current node */
4668 default:
4669 return(child);
4670 }
4671 }
4672 return(child);
4673}
4674
4675/**
4676 * xmlValidateElementType:
4677 * @ctxt: the validation context
4678 *
4679 * Try to validate the content model of an element internal function
4680 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004681 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4682 * reference is found and -3 if the validation succeeded but
4683 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004684 */
4685
4686static int
4687xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004688 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004689 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004690
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004691 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004692 if ((NODE == NULL) && (CONT == NULL))
4693 return(1);
4694 if ((NODE == NULL) &&
4695 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4696 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4697 return(1);
4698 }
4699 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004700 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004701 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004702
4703 /*
4704 * We arrive here when more states need to be examined
4705 */
4706cont:
4707
4708 /*
4709 * We just recovered from a rollback generated by a possible
4710 * epsilon transition, go directly to the analysis phase
4711 */
4712 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004713 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004714 DEBUG_VALID_STATE(NODE, CONT)
4715 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004716 goto analyze;
4717 }
4718
4719 DEBUG_VALID_STATE(NODE, CONT)
4720 /*
4721 * we may have to save a backup state here. This is the equivalent
4722 * of handling epsilon transition in NFAs.
4723 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004724 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004725 ((CONT->parent == NULL) ||
4726 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004727 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004728 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004729 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004730 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004731 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4732 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004733 }
4734
4735
4736 /*
4737 * Check first if the content matches
4738 */
4739 switch (CONT->type) {
4740 case XML_ELEMENT_CONTENT_PCDATA:
4741 if (NODE == NULL) {
4742 DEBUG_VALID_MSG("pcdata failed no node");
4743 ret = 0;
4744 break;
4745 }
4746 if (NODE->type == XML_TEXT_NODE) {
4747 DEBUG_VALID_MSG("pcdata found, skip to next");
4748 /*
4749 * go to next element in the content model
4750 * skipping ignorable elems
4751 */
4752 do {
4753 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004754 NODE = xmlValidateSkipIgnorable(NODE);
4755 if ((NODE != NULL) &&
4756 (NODE->type == XML_ENTITY_REF_NODE))
4757 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004758 } while ((NODE != NULL) &&
4759 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004760 (NODE->type != XML_TEXT_NODE) &&
4761 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004762 ret = 1;
4763 break;
4764 } else {
4765 DEBUG_VALID_MSG("pcdata failed");
4766 ret = 0;
4767 break;
4768 }
4769 break;
4770 case XML_ELEMENT_CONTENT_ELEMENT:
4771 if (NODE == NULL) {
4772 DEBUG_VALID_MSG("element failed no node");
4773 ret = 0;
4774 break;
4775 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004776 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4777 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004778 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004779 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4780 ret = (CONT->prefix == NULL);
4781 } else if (CONT->prefix == NULL) {
4782 ret = 0;
4783 } else {
4784 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4785 }
4786 }
4787 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004788 DEBUG_VALID_MSG("element found, skip to next");
4789 /*
4790 * go to next element in the content model
4791 * skipping ignorable elems
4792 */
4793 do {
4794 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004795 NODE = xmlValidateSkipIgnorable(NODE);
4796 if ((NODE != NULL) &&
4797 (NODE->type == XML_ENTITY_REF_NODE))
4798 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004799 } while ((NODE != NULL) &&
4800 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004801 (NODE->type != XML_TEXT_NODE) &&
4802 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004803 } else {
4804 DEBUG_VALID_MSG("element failed");
4805 ret = 0;
4806 break;
4807 }
4808 break;
4809 case XML_ELEMENT_CONTENT_OR:
4810 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004811 * Small optimization.
4812 */
4813 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4814 if ((NODE == NULL) ||
4815 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4816 DEPTH++;
4817 CONT = CONT->c2;
4818 goto cont;
4819 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004820 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4821 ret = (CONT->c1->prefix == NULL);
4822 } else if (CONT->c1->prefix == NULL) {
4823 ret = 0;
4824 } else {
4825 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4826 }
4827 if (ret == 0) {
4828 DEPTH++;
4829 CONT = CONT->c2;
4830 goto cont;
4831 }
Daniel Veillard85349052001-04-20 13:48:21 +00004832 }
4833
4834 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004835 * save the second branch 'or' branch
4836 */
4837 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004838 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4839 OCCURS, ROLLBACK_OR) < 0)
4840 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004841 DEPTH++;
4842 CONT = CONT->c1;
4843 goto cont;
4844 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004845 /*
4846 * Small optimization.
4847 */
4848 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4849 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4850 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4851 if ((NODE == NULL) ||
4852 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4853 DEPTH++;
4854 CONT = CONT->c2;
4855 goto cont;
4856 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004857 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4858 ret = (CONT->c1->prefix == NULL);
4859 } else if (CONT->c1->prefix == NULL) {
4860 ret = 0;
4861 } else {
4862 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4863 }
4864 if (ret == 0) {
4865 DEPTH++;
4866 CONT = CONT->c2;
4867 goto cont;
4868 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004869 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004870 DEPTH++;
4871 CONT = CONT->c1;
4872 goto cont;
4873 }
4874
4875 /*
4876 * At this point handle going up in the tree
4877 */
4878 if (ret == -1) {
4879 DEBUG_VALID_MSG("error found returning");
4880 return(ret);
4881 }
4882analyze:
4883 while (CONT != NULL) {
4884 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004885 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004886 * this level.
4887 */
4888 if (ret == 0) {
4889 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004890 xmlNodePtr cur;
4891
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004892 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004893 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004894 DEBUG_VALID_MSG("Once branch failed, rollback");
4895 if (vstateVPop(ctxt) < 0 ) {
4896 DEBUG_VALID_MSG("exhaustion, failed");
4897 return(0);
4898 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004899 if (cur != ctxt->vstate->node)
4900 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004901 goto cont;
4902 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004903 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004904 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004905 DEBUG_VALID_MSG("Plus branch failed, rollback");
4906 if (vstateVPop(ctxt) < 0 ) {
4907 DEBUG_VALID_MSG("exhaustion, failed");
4908 return(0);
4909 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004910 if (cur != ctxt->vstate->node)
4911 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004912 goto cont;
4913 }
4914 DEBUG_VALID_MSG("Plus branch found");
4915 ret = 1;
4916 break;
4917 case XML_ELEMENT_CONTENT_MULT:
4918#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004919 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004920 DEBUG_VALID_MSG("Mult branch failed");
4921 } else {
4922 DEBUG_VALID_MSG("Mult branch found");
4923 }
4924#endif
4925 ret = 1;
4926 break;
4927 case XML_ELEMENT_CONTENT_OPT:
4928 DEBUG_VALID_MSG("Option branch failed");
4929 ret = 1;
4930 break;
4931 }
4932 } else {
4933 switch (CONT->ocur) {
4934 case XML_ELEMENT_CONTENT_OPT:
4935 DEBUG_VALID_MSG("Option branch succeeded");
4936 ret = 1;
4937 break;
4938 case XML_ELEMENT_CONTENT_ONCE:
4939 DEBUG_VALID_MSG("Once branch succeeded");
4940 ret = 1;
4941 break;
4942 case XML_ELEMENT_CONTENT_PLUS:
4943 if (STATE == ROLLBACK_PARENT) {
4944 DEBUG_VALID_MSG("Plus branch rollback");
4945 ret = 1;
4946 break;
4947 }
4948 if (NODE == NULL) {
4949 DEBUG_VALID_MSG("Plus branch exhausted");
4950 ret = 1;
4951 break;
4952 }
4953 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004954 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004955 goto cont;
4956 case XML_ELEMENT_CONTENT_MULT:
4957 if (STATE == ROLLBACK_PARENT) {
4958 DEBUG_VALID_MSG("Mult branch rollback");
4959 ret = 1;
4960 break;
4961 }
4962 if (NODE == NULL) {
4963 DEBUG_VALID_MSG("Mult branch exhausted");
4964 ret = 1;
4965 break;
4966 }
4967 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004968 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004969 goto cont;
4970 }
4971 }
4972 STATE = 0;
4973
4974 /*
4975 * Then act accordingly at the parent level
4976 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004977 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004978 if (CONT->parent == NULL)
4979 break;
4980
4981 switch (CONT->parent->type) {
4982 case XML_ELEMENT_CONTENT_PCDATA:
4983 DEBUG_VALID_MSG("Error: parent pcdata");
4984 return(-1);
4985 case XML_ELEMENT_CONTENT_ELEMENT:
4986 DEBUG_VALID_MSG("Error: parent element");
4987 return(-1);
4988 case XML_ELEMENT_CONTENT_OR:
4989 if (ret == 1) {
4990 DEBUG_VALID_MSG("Or succeeded");
4991 CONT = CONT->parent;
4992 DEPTH--;
4993 } else {
4994 DEBUG_VALID_MSG("Or failed");
4995 CONT = CONT->parent;
4996 DEPTH--;
4997 }
4998 break;
4999 case XML_ELEMENT_CONTENT_SEQ:
5000 if (ret == 0) {
5001 DEBUG_VALID_MSG("Sequence failed");
5002 CONT = CONT->parent;
5003 DEPTH--;
5004 } else if (CONT == CONT->parent->c1) {
5005 DEBUG_VALID_MSG("Sequence testing 2nd branch");
5006 CONT = CONT->parent->c2;
5007 goto cont;
5008 } else {
5009 DEBUG_VALID_MSG("Sequence succeeded");
5010 CONT = CONT->parent;
5011 DEPTH--;
5012 }
5013 }
5014 }
5015 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005016 xmlNodePtr cur;
5017
5018 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005019 DEBUG_VALID_MSG("Failed, remaining input, rollback");
5020 if (vstateVPop(ctxt) < 0 ) {
5021 DEBUG_VALID_MSG("exhaustion, failed");
5022 return(0);
5023 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005024 if (cur != ctxt->vstate->node)
5025 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005026 goto cont;
5027 }
5028 if (ret == 0) {
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("Failure, 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 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005041 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005042}
Daniel Veillard23e73572002-09-19 19:56:43 +00005043#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005044
5045/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00005046 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005047 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00005048 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005049 * @content: An element
5050 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5051 *
5052 * This will dump the list of elements to the buffer
5053 * Intended just for the debug routine
5054 */
5055static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00005056xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005057 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00005058 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005059
5060 if (node == NULL) return;
5061 if (glob) strcat(buf, "(");
5062 cur = node;
5063 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005064 len = strlen(buf);
5065 if (size - len < 50) {
5066 if ((size - len > 4) && (buf[len - 1] != '.'))
5067 strcat(buf, " ...");
5068 return;
5069 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005070 switch (cur->type) {
5071 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005072 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005073 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005074 if ((size - len > 4) && (buf[len - 1] != '.'))
5075 strcat(buf, " ...");
5076 return;
5077 }
5078 strcat(buf, (char *) cur->ns->prefix);
5079 strcat(buf, ":");
5080 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005081 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005082 if ((size - len > 4) && (buf[len - 1] != '.'))
5083 strcat(buf, " ...");
5084 return;
5085 }
5086 strcat(buf, (char *) cur->name);
5087 if (cur->next != NULL)
5088 strcat(buf, " ");
5089 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005090 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005091 if (xmlIsBlankNode(cur))
5092 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005093 case XML_CDATA_SECTION_NODE:
5094 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005095 strcat(buf, "CDATA");
5096 if (cur->next != NULL)
5097 strcat(buf, " ");
5098 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005099 case XML_ATTRIBUTE_NODE:
5100 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005101#ifdef LIBXML_DOCB_ENABLED
5102 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005103#endif
5104 case XML_HTML_DOCUMENT_NODE:
5105 case XML_DOCUMENT_TYPE_NODE:
5106 case XML_DOCUMENT_FRAG_NODE:
5107 case XML_NOTATION_NODE:
5108 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005109 strcat(buf, "???");
5110 if (cur->next != NULL)
5111 strcat(buf, " ");
5112 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005113 case XML_ENTITY_NODE:
5114 case XML_PI_NODE:
5115 case XML_DTD_NODE:
5116 case XML_COMMENT_NODE:
5117 case XML_ELEMENT_DECL:
5118 case XML_ATTRIBUTE_DECL:
5119 case XML_ENTITY_DECL:
5120 case XML_XINCLUDE_START:
5121 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005122 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005123 }
5124 cur = cur->next;
5125 }
5126 if (glob) strcat(buf, ")");
5127}
5128
5129/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005130 * xmlValidateElementContent:
5131 * @ctxt: the validation context
5132 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005133 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005134 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005135 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005136 *
5137 * Try to validate the content model of an element
5138 *
5139 * returns 1 if valid or 0 if not and -1 in case of error
5140 */
5141
5142static int
5143xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005144 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00005145 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00005146#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00005147 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00005148#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00005149 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005150 xmlElementContentPtr cont;
5151 const xmlChar *name;
5152
5153 if (elemDecl == NULL)
5154 return(-1);
5155 cont = elemDecl->content;
5156 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005157
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005158#ifdef LIBXML_REGEXP_ENABLED
5159 /* Build the regexp associated to the content model */
5160 if (elemDecl->contModel == NULL)
5161 ret = xmlValidBuildContentModel(ctxt, elemDecl);
5162 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005163 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005164 } else {
5165 xmlRegExecCtxtPtr exec;
5166
Daniel Veillardec498e12003-02-05 11:01:50 +00005167 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5168 return(-1);
5169 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005170 ctxt->nodeMax = 0;
5171 ctxt->nodeNr = 0;
5172 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005173 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5174 if (exec != NULL) {
5175 cur = child;
5176 while (cur != NULL) {
5177 switch (cur->type) {
5178 case XML_ENTITY_REF_NODE:
5179 /*
5180 * Push the current node to be able to roll back
5181 * and process within the entity
5182 */
5183 if ((cur->children != NULL) &&
5184 (cur->children->children != NULL)) {
5185 nodeVPush(ctxt, cur);
5186 cur = cur->children->children;
5187 continue;
5188 }
5189 break;
5190 case XML_TEXT_NODE:
5191 if (xmlIsBlankNode(cur))
5192 break;
5193 ret = 0;
5194 goto fail;
5195 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00005196 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005197 ret = 0;
5198 goto fail;
5199 case XML_ELEMENT_NODE:
5200 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005201 xmlChar fn[50];
5202 xmlChar *fullname;
5203
5204 fullname = xmlBuildQName(cur->name,
5205 cur->ns->prefix, fn, 50);
5206 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005207 ret = -1;
5208 goto fail;
5209 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005210 ret = xmlRegExecPushString(exec, fullname, NULL);
5211 if ((fullname != fn) && (fullname != cur->name))
5212 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005213 } else {
5214 ret = xmlRegExecPushString(exec, cur->name, NULL);
5215 }
5216 break;
5217 default:
5218 break;
5219 }
5220 /*
5221 * Switch to next element
5222 */
5223 cur = cur->next;
5224 while (cur == NULL) {
5225 cur = nodeVPop(ctxt);
5226 if (cur == NULL)
5227 break;
5228 cur = cur->next;
5229 }
5230 }
5231 ret = xmlRegExecPushString(exec, NULL, NULL);
5232fail:
5233 xmlRegFreeExecCtxt(exec);
5234 }
5235 }
5236#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005237 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005238 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005239 */
5240 ctxt->vstateMax = 8;
5241 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5242 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5243 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005244 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005245 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005246 }
5247 /*
5248 * The first entry in the stack is reserved to the current state
5249 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005250 ctxt->nodeMax = 0;
5251 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005252 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005253 ctxt->vstate = &ctxt->vstateTab[0];
5254 ctxt->vstateNr = 1;
5255 CONT = cont;
5256 NODE = child;
5257 DEPTH = 0;
5258 OCCURS = 0;
5259 STATE = 0;
5260 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005261 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005262 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5263 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005264 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005265 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005266 /*
5267 * An entities reference appeared at this level.
5268 * Buid a minimal representation of this node content
5269 * sufficient to run the validation process on it
5270 */
5271 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005272 cur = child;
5273 while (cur != NULL) {
5274 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005275 case XML_ENTITY_REF_NODE:
5276 /*
5277 * Push the current node to be able to roll back
5278 * and process within the entity
5279 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005280 if ((cur->children != NULL) &&
5281 (cur->children->children != NULL)) {
5282 nodeVPush(ctxt, cur);
5283 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005284 continue;
5285 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005286 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005287 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005288 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005289 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005290 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005291 case XML_CDATA_SECTION_NODE:
5292 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005293 case XML_ELEMENT_NODE:
5294 /*
5295 * Allocate a new node and minimally fills in
5296 * what's required
5297 */
5298 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5299 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005300 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005301 xmlFreeNodeList(repl);
5302 ret = -1;
5303 goto done;
5304 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005305 tmp->type = cur->type;
5306 tmp->name = cur->name;
5307 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005308 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005309 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005310 if (repl == NULL)
5311 repl = last = tmp;
5312 else {
5313 last->next = tmp;
5314 last = tmp;
5315 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005316 if (cur->type == XML_CDATA_SECTION_NODE) {
5317 /*
5318 * E59 spaces in CDATA does not match the
5319 * nonterminal S
5320 */
5321 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5322 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005323 break;
5324 default:
5325 break;
5326 }
5327 /*
5328 * Switch to next element
5329 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005330 cur = cur->next;
5331 while (cur == NULL) {
5332 cur = nodeVPop(ctxt);
5333 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005334 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005335 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005336 }
5337 }
5338
5339 /*
5340 * Relaunch the validation
5341 */
5342 ctxt->vstate = &ctxt->vstateTab[0];
5343 ctxt->vstateNr = 1;
5344 CONT = cont;
5345 NODE = repl;
5346 DEPTH = 0;
5347 OCCURS = 0;
5348 STATE = 0;
5349 ret = xmlValidateElementType(ctxt);
5350 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005351#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005352 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00005353 if (ctxt != NULL) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005354 char expr[5000];
5355 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005356
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005357 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005358 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005359 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005360#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005361 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005362 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005363 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005364#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005365 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005366
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005367 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005368 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5369 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5370 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005371 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005372 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5373 "Element content does not follow the DTD, expecting %s, got %s\n",
5374 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005375 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005376 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005377 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005378 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005379 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005380 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005381 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005382 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5383 "Element content does not follow the DTD\n",
5384 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005385 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005386 }
5387 ret = 0;
5388 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005389 if (ret == -3)
5390 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005391
Daniel Veillard23e73572002-09-19 19:56:43 +00005392#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005393done:
5394 /*
5395 * Deallocate the copy if done, and free up the validation stack
5396 */
5397 while (repl != NULL) {
5398 tmp = repl->next;
5399 xmlFree(repl);
5400 repl = tmp;
5401 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005402 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005403 if (ctxt->vstateTab != NULL) {
5404 xmlFree(ctxt->vstateTab);
5405 ctxt->vstateTab = NULL;
5406 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005407#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005408 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005409 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005410 if (ctxt->nodeTab != NULL) {
5411 xmlFree(ctxt->nodeTab);
5412 ctxt->nodeTab = NULL;
5413 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005414 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005415
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005416}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005417
Owen Taylor3473f882001-02-23 17:55:21 +00005418/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005419 * xmlValidateCdataElement:
5420 * @ctxt: the validation context
5421 * @doc: a document instance
5422 * @elem: an element instance
5423 *
5424 * Check that an element follows #CDATA
5425 *
5426 * returns 1 if valid or 0 otherwise
5427 */
5428static int
5429xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5430 xmlNodePtr elem) {
5431 int ret = 1;
5432 xmlNodePtr cur, child;
5433
Daniel Veillardceb09b92002-10-04 11:46:37 +00005434 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005435 return(0);
5436
5437 child = elem->children;
5438
5439 cur = child;
5440 while (cur != NULL) {
5441 switch (cur->type) {
5442 case XML_ENTITY_REF_NODE:
5443 /*
5444 * Push the current node to be able to roll back
5445 * and process within the entity
5446 */
5447 if ((cur->children != NULL) &&
5448 (cur->children->children != NULL)) {
5449 nodeVPush(ctxt, cur);
5450 cur = cur->children->children;
5451 continue;
5452 }
5453 break;
5454 case XML_COMMENT_NODE:
5455 case XML_PI_NODE:
5456 case XML_TEXT_NODE:
5457 case XML_CDATA_SECTION_NODE:
5458 break;
5459 default:
5460 ret = 0;
5461 goto done;
5462 }
5463 /*
5464 * Switch to next element
5465 */
5466 cur = cur->next;
5467 while (cur == NULL) {
5468 cur = nodeVPop(ctxt);
5469 if (cur == NULL)
5470 break;
5471 cur = cur->next;
5472 }
5473 }
5474done:
5475 ctxt->nodeMax = 0;
5476 ctxt->nodeNr = 0;
5477 if (ctxt->nodeTab != NULL) {
5478 xmlFree(ctxt->nodeTab);
5479 ctxt->nodeTab = NULL;
5480 }
5481 return(ret);
5482}
5483
5484/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005485 * xmlValidateCheckMixed:
5486 * @ctxt: the validation context
5487 * @cont: the mixed content model
5488 * @qname: the qualified name as appearing in the serialization
5489 *
5490 * Check if the given node is part of the content model.
5491 *
5492 * Returns 1 if yes, 0 if no, -1 in case of error
5493 */
5494static int
William M. Brackedb65a72004-02-06 07:36:04 +00005495xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005496 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005497 const xmlChar *name;
5498 int plen;
5499 name = xmlSplitQName3(qname, &plen);
5500
5501 if (name == NULL) {
5502 while (cont != NULL) {
5503 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5504 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5505 return(1);
5506 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5507 (cont->c1 != NULL) &&
5508 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5509 if ((cont->c1->prefix == NULL) &&
5510 (xmlStrEqual(cont->c1->name, qname)))
5511 return(1);
5512 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5513 (cont->c1 == NULL) ||
5514 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005515 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5516 "Internal: MIXED struct corrupted\n",
5517 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005518 break;
5519 }
5520 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005521 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005522 } else {
5523 while (cont != NULL) {
5524 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5525 if ((cont->prefix != NULL) &&
5526 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5527 (xmlStrEqual(cont->name, name)))
5528 return(1);
5529 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5530 (cont->c1 != NULL) &&
5531 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5532 if ((cont->c1->prefix != NULL) &&
5533 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5534 (xmlStrEqual(cont->c1->name, name)))
5535 return(1);
5536 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5537 (cont->c1 == NULL) ||
5538 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005539 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5540 "Internal: MIXED struct corrupted\n",
5541 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005542 break;
5543 }
5544 cont = cont->c2;
5545 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005546 }
5547 return(0);
5548}
5549
5550/**
5551 * xmlValidGetElemDecl:
5552 * @ctxt: the validation context
5553 * @doc: a document instance
5554 * @elem: an element instance
5555 * @extsubset: pointer, (out) indicate if the declaration was found
5556 * in the external subset.
5557 *
5558 * Finds a declaration associated to an element in the document.
5559 *
5560 * returns the pointer to the declaration or NULL if not found.
5561 */
5562static xmlElementPtr
5563xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5564 xmlNodePtr elem, int *extsubset) {
5565 xmlElementPtr elemDecl = NULL;
5566 const xmlChar *prefix = NULL;
5567
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005568 if ((ctxt == NULL) || (doc == NULL) ||
5569 (elem == NULL) || (elem->name == NULL))
5570 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005571 if (extsubset != NULL)
5572 *extsubset = 0;
5573
5574 /*
5575 * Fetch the declaration for the qualified name
5576 */
5577 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5578 prefix = elem->ns->prefix;
5579
5580 if (prefix != NULL) {
5581 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5582 elem->name, prefix);
5583 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5584 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5585 elem->name, prefix);
5586 if ((elemDecl != NULL) && (extsubset != NULL))
5587 *extsubset = 1;
5588 }
5589 }
5590
5591 /*
5592 * Fetch the declaration for the non qualified name
5593 * This is "non-strict" validation should be done on the
5594 * full QName but in that case being flexible makes sense.
5595 */
5596 if (elemDecl == NULL) {
5597 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5598 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5599 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5600 if ((elemDecl != NULL) && (extsubset != NULL))
5601 *extsubset = 1;
5602 }
5603 }
5604 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005605 xmlErrValidNode(ctxt, elem,
5606 XML_DTD_UNKNOWN_ELEM,
5607 "No declaration for element %s\n",
5608 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005609 }
5610 return(elemDecl);
5611}
5612
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005613#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005614/**
5615 * xmlValidatePushElement:
5616 * @ctxt: the validation context
5617 * @doc: a document instance
5618 * @elem: an element instance
5619 * @qname: the qualified name as appearing in the serialization
5620 *
5621 * Push a new element start on the validation stack.
5622 *
5623 * returns 1 if no validation problem was found or 0 otherwise
5624 */
5625int
5626xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5627 xmlNodePtr elem, const xmlChar *qname) {
5628 int ret = 1;
5629 xmlElementPtr eDecl;
5630 int extsubset = 0;
5631
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005632 if (ctxt == NULL)
5633 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005634/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005635 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5636 xmlValidStatePtr state = ctxt->vstate;
5637 xmlElementPtr elemDecl;
5638
5639 /*
5640 * Check the new element agaisnt the content model of the new elem.
5641 */
5642 if (state->elemDecl != NULL) {
5643 elemDecl = state->elemDecl;
5644
5645 switch(elemDecl->etype) {
5646 case XML_ELEMENT_TYPE_UNDEFINED:
5647 ret = 0;
5648 break;
5649 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005650 xmlErrValidNode(ctxt, state->node,
5651 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005652 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005653 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005654 ret = 0;
5655 break;
5656 case XML_ELEMENT_TYPE_ANY:
5657 /* I don't think anything is required then */
5658 break;
5659 case XML_ELEMENT_TYPE_MIXED:
5660 /* simple case of declared as #PCDATA */
5661 if ((elemDecl->content != NULL) &&
5662 (elemDecl->content->type ==
5663 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005664 xmlErrValidNode(ctxt, state->node,
5665 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005666 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005667 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005668 ret = 0;
5669 } else {
5670 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5671 qname);
5672 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005673 xmlErrValidNode(ctxt, state->node,
5674 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005675 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005676 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005677 }
5678 }
5679 break;
5680 case XML_ELEMENT_TYPE_ELEMENT:
5681 /*
5682 * TODO:
5683 * VC: Standalone Document Declaration
5684 * - element types with element content, if white space
5685 * occurs directly within any instance of those types.
5686 */
5687 if (state->exec != NULL) {
5688 ret = xmlRegExecPushString(state->exec, qname, NULL);
5689 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005690 xmlErrValidNode(ctxt, state->node,
5691 XML_DTD_CONTENT_MODEL,
5692 "Element %s content does not follow the DTD, Misplaced %s\n",
5693 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005694 ret = 0;
5695 } else {
5696 ret = 1;
5697 }
5698 }
5699 break;
5700 }
5701 }
5702 }
5703 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5704 vstateVPush(ctxt, eDecl, elem);
5705 return(ret);
5706}
5707
5708/**
5709 * xmlValidatePushCData:
5710 * @ctxt: the validation context
5711 * @data: some character data read
5712 * @len: the lenght of the data
5713 *
5714 * check the CData parsed for validation in the current stack
5715 *
5716 * returns 1 if no validation problem was found or 0 otherwise
5717 */
5718int
5719xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5720 int ret = 1;
5721
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005722/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005723 if (ctxt == NULL)
5724 return(0);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005725 if (len <= 0)
5726 return(ret);
5727 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5728 xmlValidStatePtr state = ctxt->vstate;
5729 xmlElementPtr elemDecl;
5730
5731 /*
5732 * Check the new element agaisnt the content model of the new elem.
5733 */
5734 if (state->elemDecl != NULL) {
5735 elemDecl = state->elemDecl;
5736
5737 switch(elemDecl->etype) {
5738 case XML_ELEMENT_TYPE_UNDEFINED:
5739 ret = 0;
5740 break;
5741 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005742 xmlErrValidNode(ctxt, state->node,
5743 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005744 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005745 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005746 ret = 0;
5747 break;
5748 case XML_ELEMENT_TYPE_ANY:
5749 break;
5750 case XML_ELEMENT_TYPE_MIXED:
5751 break;
5752 case XML_ELEMENT_TYPE_ELEMENT:
5753 if (len > 0) {
5754 int i;
5755
5756 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005757 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005758 xmlErrValidNode(ctxt, state->node,
5759 XML_DTD_CONTENT_MODEL,
5760 "Element %s content does not follow the DTD, Text not allowed\n",
5761 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005762 ret = 0;
5763 goto done;
5764 }
5765 }
5766 /*
5767 * TODO:
5768 * VC: Standalone Document Declaration
5769 * element types with element content, if white space
5770 * occurs directly within any instance of those types.
5771 */
5772 }
5773 break;
5774 }
5775 }
5776 }
5777done:
5778 return(ret);
5779}
5780
5781/**
5782 * xmlValidatePopElement:
5783 * @ctxt: the validation context
5784 * @doc: a document instance
5785 * @elem: an element instance
5786 * @qname: the qualified name as appearing in the serialization
5787 *
5788 * Pop the element end from the validation stack.
5789 *
5790 * returns 1 if no validation problem was found or 0 otherwise
5791 */
5792int
5793xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005794 xmlNodePtr elem ATTRIBUTE_UNUSED,
5795 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005796 int ret = 1;
5797
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005798 if (ctxt == NULL)
5799 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005800/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005801 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5802 xmlValidStatePtr state = ctxt->vstate;
5803 xmlElementPtr elemDecl;
5804
5805 /*
5806 * Check the new element agaisnt the content model of the new elem.
5807 */
5808 if (state->elemDecl != NULL) {
5809 elemDecl = state->elemDecl;
5810
5811 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5812 if (state->exec != NULL) {
5813 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5814 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005815 xmlErrValidNode(ctxt, state->node,
5816 XML_DTD_CONTENT_MODEL,
5817 "Element %s content does not follow the DTD, Expecting more child\n",
5818 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005819 } else {
5820 /*
5821 * previous validation errors should not generate
5822 * a new one here
5823 */
5824 ret = 1;
5825 }
5826 }
5827 }
5828 }
5829 vstateVPop(ctxt);
5830 }
5831 return(ret);
5832}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005833#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005834
5835/**
Owen Taylor3473f882001-02-23 17:55:21 +00005836 * xmlValidateOneElement:
5837 * @ctxt: the validation context
5838 * @doc: a document instance
5839 * @elem: an element instance
5840 *
5841 * Try to validate a single element and it's attributes,
5842 * basically it does the following checks as described by the
5843 * XML-1.0 recommendation:
5844 * - [ VC: Element Valid ]
5845 * - [ VC: Required Attribute ]
5846 * Then call xmlValidateOneAttribute() for each attribute present.
5847 *
5848 * The ID/IDREF checkings are done separately
5849 *
5850 * returns 1 if valid or 0 otherwise
5851 */
5852
5853int
5854xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5855 xmlNodePtr elem) {
5856 xmlElementPtr elemDecl = NULL;
5857 xmlElementContentPtr cont;
5858 xmlAttributePtr attr;
5859 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005860 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005861 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005862 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005863
5864 CHECK_DTD;
5865
5866 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005867 switch (elem->type) {
5868 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005869 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5870 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005871 return(0);
5872 case XML_TEXT_NODE:
5873 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005874 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5875 "Text element has children !\n",
5876 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005877 return(0);
5878 }
Owen Taylor3473f882001-02-23 17:55:21 +00005879 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005880 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5881 "Text element has namespace !\n",
5882 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005883 return(0);
5884 }
Owen Taylor3473f882001-02-23 17:55:21 +00005885 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005886 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5887 "Text element has no content !\n",
5888 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005889 return(0);
5890 }
5891 return(1);
5892 case XML_XINCLUDE_START:
5893 case XML_XINCLUDE_END:
5894 return(1);
5895 case XML_CDATA_SECTION_NODE:
5896 case XML_ENTITY_REF_NODE:
5897 case XML_PI_NODE:
5898 case XML_COMMENT_NODE:
5899 return(1);
5900 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005901 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5902 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005903 return(0);
5904 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005905 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5906 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005907 return(0);
5908 case XML_DOCUMENT_NODE:
5909 case XML_DOCUMENT_TYPE_NODE:
5910 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005911 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5912 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005913 return(0);
5914 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005915 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5916 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005917 return(0);
5918 case XML_ELEMENT_NODE:
5919 break;
5920 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005921 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5922 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005923 return(0);
5924 }
Owen Taylor3473f882001-02-23 17:55:21 +00005925
5926 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005927 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005928 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005929 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5930 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005931 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005932
Daniel Veillardea7751d2002-12-20 00:16:24 +00005933 /*
5934 * If vstateNr is not zero that means continuous validation is
5935 * activated, do not try to check the content model at that level.
5936 */
5937 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005938 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005939 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005940 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005941 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5942 "No declaration for element %s\n",
5943 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005944 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005945 case XML_ELEMENT_TYPE_EMPTY:
5946 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005947 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005948 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005949 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005950 ret = 0;
5951 }
5952 break;
5953 case XML_ELEMENT_TYPE_ANY:
5954 /* I don't think anything is required then */
5955 break;
5956 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005957
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005958 /* simple case of declared as #PCDATA */
5959 if ((elemDecl->content != NULL) &&
5960 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5961 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5962 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005963 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005964 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005965 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005966 }
5967 break;
5968 }
Owen Taylor3473f882001-02-23 17:55:21 +00005969 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005970 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005971 while (child != NULL) {
5972 if (child->type == XML_ELEMENT_NODE) {
5973 name = child->name;
5974 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005975 xmlChar fn[50];
5976 xmlChar *fullname;
5977
5978 fullname = xmlBuildQName(child->name, child->ns->prefix,
5979 fn, 50);
5980 if (fullname == NULL)
5981 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005982 cont = elemDecl->content;
5983 while (cont != NULL) {
5984 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005985 if (xmlStrEqual(cont->name, fullname))
5986 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005987 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5988 (cont->c1 != NULL) &&
5989 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005990 if (xmlStrEqual(cont->c1->name, fullname))
5991 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005992 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5993 (cont->c1 == NULL) ||
5994 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005995 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5996 "Internal: MIXED struct corrupted\n",
5997 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005998 break;
5999 }
6000 cont = cont->c2;
6001 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00006002 if ((fullname != fn) && (fullname != child->name))
6003 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00006004 if (cont != NULL)
6005 goto child_ok;
6006 }
6007 cont = elemDecl->content;
6008 while (cont != NULL) {
6009 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6010 if (xmlStrEqual(cont->name, name)) break;
6011 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6012 (cont->c1 != NULL) &&
6013 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
6014 if (xmlStrEqual(cont->c1->name, name)) break;
6015 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6016 (cont->c1 == NULL) ||
6017 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006018 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
6019 "Internal: MIXED struct corrupted\n",
6020 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006021 break;
6022 }
6023 cont = cont->c2;
6024 }
6025 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006026 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006027 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006028 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006029 ret = 0;
6030 }
6031 }
6032child_ok:
6033 child = child->next;
6034 }
6035 break;
6036 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006037 if ((doc->standalone == 1) && (extsubset == 1)) {
6038 /*
6039 * VC: Standalone Document Declaration
6040 * - element types with element content, if white space
6041 * occurs directly within any instance of those types.
6042 */
6043 child = elem->children;
6044 while (child != NULL) {
6045 if (child->type == XML_TEXT_NODE) {
6046 const xmlChar *content = child->content;
6047
William M. Brack76e95df2003-10-18 16:20:14 +00006048 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006049 content++;
6050 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006051 xmlErrValidNode(ctxt, elem,
6052 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006053"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006054 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006055 ret = 0;
6056 break;
6057 }
6058 }
6059 child =child->next;
6060 }
6061 }
Owen Taylor3473f882001-02-23 17:55:21 +00006062 child = elem->children;
6063 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00006064 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006065 if (tmp <= 0)
6066 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006067 break;
6068 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00006069 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00006070
6071 /* [ VC: Required Attribute ] */
6072 attr = elemDecl->attributes;
6073 while (attr != NULL) {
6074 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006075 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006076
Daniel Veillarde4301c82002-02-13 13:32:35 +00006077 if ((attr->prefix == NULL) &&
6078 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6079 xmlNsPtr ns;
6080
6081 ns = elem->nsDef;
6082 while (ns != NULL) {
6083 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006084 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006085 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006086 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006087 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6088 xmlNsPtr ns;
6089
6090 ns = elem->nsDef;
6091 while (ns != NULL) {
6092 if (xmlStrEqual(attr->name, ns->prefix))
6093 goto found;
6094 ns = ns->next;
6095 }
6096 } else {
6097 xmlAttrPtr attrib;
6098
6099 attrib = elem->properties;
6100 while (attrib != NULL) {
6101 if (xmlStrEqual(attrib->name, attr->name)) {
6102 if (attr->prefix != NULL) {
6103 xmlNsPtr nameSpace = attrib->ns;
6104
6105 if (nameSpace == NULL)
6106 nameSpace = elem->ns;
6107 /*
6108 * qualified names handling is problematic, having a
6109 * different prefix should be possible but DTDs don't
6110 * allow to define the URI instead of the prefix :-(
6111 */
6112 if (nameSpace == NULL) {
6113 if (qualified < 0)
6114 qualified = 0;
6115 } else if (!xmlStrEqual(nameSpace->prefix,
6116 attr->prefix)) {
6117 if (qualified < 1)
6118 qualified = 1;
6119 } else
6120 goto found;
6121 } else {
6122 /*
6123 * We should allow applications to define namespaces
6124 * for their application even if the DTD doesn't
6125 * carry one, otherwise, basically we would always
6126 * break.
6127 */
6128 goto found;
6129 }
6130 }
6131 attrib = attrib->next;
6132 }
Owen Taylor3473f882001-02-23 17:55:21 +00006133 }
6134 if (qualified == -1) {
6135 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006136 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006137 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006138 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006139 ret = 0;
6140 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006141 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006142 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00006143 elem->name, attr->prefix,attr->name);
6144 ret = 0;
6145 }
6146 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006147 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006148 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006149 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006150 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006151 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006152 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006153 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006154 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006155 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
6156 /*
6157 * Special tests checking #FIXED namespace declarations
6158 * have the right value since this is not done as an
6159 * attribute checking
6160 */
6161 if ((attr->prefix == NULL) &&
6162 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6163 xmlNsPtr ns;
6164
6165 ns = elem->nsDef;
6166 while (ns != NULL) {
6167 if (ns->prefix == NULL) {
6168 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006169 xmlErrValidNode(ctxt, elem,
6170 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00006171 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006172 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006173 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006174 }
6175 goto found;
6176 }
6177 ns = ns->next;
6178 }
6179 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6180 xmlNsPtr ns;
6181
6182 ns = elem->nsDef;
6183 while (ns != NULL) {
6184 if (xmlStrEqual(attr->name, ns->prefix)) {
6185 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006186 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006187 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006188 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006189 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006190 }
6191 goto found;
6192 }
6193 ns = ns->next;
6194 }
6195 }
Owen Taylor3473f882001-02-23 17:55:21 +00006196 }
6197found:
6198 attr = attr->nexth;
6199 }
6200 return(ret);
6201}
6202
6203/**
6204 * xmlValidateRoot:
6205 * @ctxt: the validation context
6206 * @doc: a document instance
6207 *
6208 * Try to validate a the root element
6209 * basically it does the following check as described by the
6210 * XML-1.0 recommendation:
6211 * - [ VC: Root Element Type ]
6212 * it doesn't try to recurse or apply other check to the element
6213 *
6214 * returns 1 if valid or 0 otherwise
6215 */
6216
6217int
6218xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6219 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006220 int ret;
6221
Owen Taylor3473f882001-02-23 17:55:21 +00006222 if (doc == NULL) return(0);
6223
6224 root = xmlDocGetRootElement(doc);
6225 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006226 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6227 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006228 return(0);
6229 }
6230
6231 /*
6232 * When doing post validation against a separate DTD, those may
6233 * no internal subset has been generated
6234 */
6235 if ((doc->intSubset != NULL) &&
6236 (doc->intSubset->name != NULL)) {
6237 /*
6238 * Check first the document root against the NQName
6239 */
6240 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6241 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006242 xmlChar fn[50];
6243 xmlChar *fullname;
6244
6245 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6246 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006247 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006248 return(0);
6249 }
6250 ret = xmlStrEqual(doc->intSubset->name, fullname);
6251 if ((fullname != fn) && (fullname != root->name))
6252 xmlFree(fullname);
6253 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006254 goto name_ok;
6255 }
6256 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6257 (xmlStrEqual(root->name, BAD_CAST "html")))
6258 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006259 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6260 "root and DTD name do not match '%s' and '%s'\n",
6261 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006262 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006263 }
6264 }
6265name_ok:
6266 return(1);
6267}
6268
6269
6270/**
6271 * xmlValidateElement:
6272 * @ctxt: the validation context
6273 * @doc: a document instance
6274 * @elem: an element instance
6275 *
6276 * Try to validate the subtree under an element
6277 *
6278 * returns 1 if valid or 0 otherwise
6279 */
6280
6281int
6282xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6283 xmlNodePtr child;
6284 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006285 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006286 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006287 int ret = 1;
6288
6289 if (elem == NULL) return(0);
6290
6291 /*
6292 * XInclude elements were added after parsing in the infoset,
6293 * they don't really mean anything validation wise.
6294 */
6295 if ((elem->type == XML_XINCLUDE_START) ||
6296 (elem->type == XML_XINCLUDE_END))
6297 return(1);
6298
6299 CHECK_DTD;
6300
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006301 /*
6302 * Entities references have to be handled separately
6303 */
6304 if (elem->type == XML_ENTITY_REF_NODE) {
6305 return(1);
6306 }
6307
Owen Taylor3473f882001-02-23 17:55:21 +00006308 ret &= xmlValidateOneElement(ctxt, doc, elem);
Daniel Veillard8874b942005-08-25 13:19:21 +00006309 if (elem->type == XML_ELEMENT_NODE) {
6310 attr = elem->properties;
6311 while (attr != NULL) {
6312 value = xmlNodeListGetString(doc, attr->children, 0);
6313 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6314 if (value != NULL)
6315 xmlFree((char *)value);
6316 attr= attr->next;
6317 }
6318 ns = elem->nsDef;
6319 while (ns != NULL) {
6320 if (elem->ns == NULL)
6321 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6322 ns, ns->href);
6323 else
6324 ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6325 elem->ns->prefix, ns, ns->href);
6326 ns = ns->next;
6327 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006328 }
Owen Taylor3473f882001-02-23 17:55:21 +00006329 child = elem->children;
6330 while (child != NULL) {
6331 ret &= xmlValidateElement(ctxt, doc, child);
6332 child = child->next;
6333 }
6334
6335 return(ret);
6336}
6337
Daniel Veillard8730c562001-02-26 10:49:57 +00006338/**
6339 * xmlValidateRef:
6340 * @ref: A reference to be validated
6341 * @ctxt: Validation context
6342 * @name: Name of ID we are searching for
6343 *
6344 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006345static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006346xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006347 const xmlChar *name) {
6348 xmlAttrPtr id;
6349 xmlAttrPtr attr;
6350
6351 if (ref == NULL)
6352 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006353 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006354 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006355 attr = ref->attr;
6356 if (attr == NULL) {
6357 xmlChar *dup, *str = NULL, *cur, save;
6358
6359 dup = xmlStrdup(name);
6360 if (dup == NULL) {
6361 ctxt->valid = 0;
6362 return;
6363 }
6364 cur = dup;
6365 while (*cur != 0) {
6366 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006367 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006368 save = *cur;
6369 *cur = 0;
6370 id = xmlGetID(ctxt->doc, str);
6371 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006372 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006373 "attribute %s line %d references an unknown ID \"%s\"\n",
6374 ref->name, ref->lineno, str);
6375 ctxt->valid = 0;
6376 }
6377 if (save == 0)
6378 break;
6379 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006380 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006381 }
6382 xmlFree(dup);
6383 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006384 id = xmlGetID(ctxt->doc, name);
6385 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006386 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006387 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006388 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006389 ctxt->valid = 0;
6390 }
6391 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6392 xmlChar *dup, *str = NULL, *cur, save;
6393
6394 dup = xmlStrdup(name);
6395 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006396 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006397 ctxt->valid = 0;
6398 return;
6399 }
6400 cur = dup;
6401 while (*cur != 0) {
6402 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006403 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006404 save = *cur;
6405 *cur = 0;
6406 id = xmlGetID(ctxt->doc, str);
6407 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006408 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006409 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006410 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006411 ctxt->valid = 0;
6412 }
6413 if (save == 0)
6414 break;
6415 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006416 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006417 }
6418 xmlFree(dup);
6419 }
6420}
6421
6422/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006423 * xmlWalkValidateList:
6424 * @data: Contents of current link
6425 * @user: Value supplied by the user
6426 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006427 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006428 */
6429static int
6430xmlWalkValidateList(const void *data, const void *user)
6431{
6432 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6433 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6434 return 1;
6435}
6436
6437/**
6438 * xmlValidateCheckRefCallback:
6439 * @ref_list: List of references
6440 * @ctxt: Validation context
6441 * @name: Name of ID we are searching for
6442 *
6443 */
6444static void
6445xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6446 const xmlChar *name) {
6447 xmlValidateMemo memo;
6448
6449 if (ref_list == NULL)
6450 return;
6451 memo.ctxt = ctxt;
6452 memo.name = name;
6453
6454 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6455
6456}
6457
6458/**
Owen Taylor3473f882001-02-23 17:55:21 +00006459 * xmlValidateDocumentFinal:
6460 * @ctxt: the validation context
6461 * @doc: a document instance
6462 *
6463 * Does the final step for the document validation once all the
6464 * incremental validation steps have been completed
6465 *
6466 * basically it does the following checks described by the XML Rec
6467 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006468 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006469 *
6470 * returns 1 if valid or 0 otherwise
6471 */
6472
6473int
6474xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6475 xmlRefTablePtr table;
6476
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006477 if (ctxt == NULL)
6478 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006479 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006480 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6481 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006482 return(0);
6483 }
6484
6485 /*
6486 * Check all the NOTATION/NOTATIONS attributes
6487 */
6488 /*
6489 * Check all the ENTITY/ENTITIES attributes definition for validity
6490 */
6491 /*
6492 * Check all the IDREF/IDREFS attributes definition for validity
6493 */
6494 table = (xmlRefTablePtr) doc->refs;
6495 ctxt->doc = doc;
6496 ctxt->valid = 1;
6497 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6498 return(ctxt->valid);
6499}
6500
6501/**
6502 * xmlValidateDtd:
6503 * @ctxt: the validation context
6504 * @doc: a document instance
6505 * @dtd: a dtd instance
6506 *
6507 * Try to validate the document against the dtd instance
6508 *
William M. Brack367df6e2004-10-23 18:14:36 +00006509 * Basically it does check all the definitions in the DtD.
6510 * Note the the internal subset (if present) is de-coupled
6511 * (i.e. not used), which could give problems if ID or IDREF
6512 * is present.
Owen Taylor3473f882001-02-23 17:55:21 +00006513 *
6514 * returns 1 if valid or 0 otherwise
6515 */
6516
6517int
6518xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6519 int ret;
William M. Brack367df6e2004-10-23 18:14:36 +00006520 xmlDtdPtr oldExt, oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006521 xmlNodePtr root;
6522
6523 if (dtd == NULL) return(0);
6524 if (doc == NULL) return(0);
6525 oldExt = doc->extSubset;
William M. Brack367df6e2004-10-23 18:14:36 +00006526 oldInt = doc->intSubset;
Owen Taylor3473f882001-02-23 17:55:21 +00006527 doc->extSubset = dtd;
William M. Brack367df6e2004-10-23 18:14:36 +00006528 doc->intSubset = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006529 ret = xmlValidateRoot(ctxt, doc);
6530 if (ret == 0) {
6531 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006532 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006533 return(ret);
6534 }
6535 if (doc->ids != NULL) {
6536 xmlFreeIDTable(doc->ids);
6537 doc->ids = NULL;
6538 }
6539 if (doc->refs != NULL) {
6540 xmlFreeRefTable(doc->refs);
6541 doc->refs = NULL;
6542 }
6543 root = xmlDocGetRootElement(doc);
6544 ret = xmlValidateElement(ctxt, doc, root);
6545 ret &= xmlValidateDocumentFinal(ctxt, doc);
6546 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006547 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006548 return(ret);
6549}
6550
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006551static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006552xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6553 const xmlChar *name ATTRIBUTE_UNUSED) {
6554 if (cur == NULL)
6555 return;
6556 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6557 xmlChar *notation = cur->content;
6558
Daniel Veillard878eab02002-02-19 13:46:09 +00006559 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006560 int ret;
6561
6562 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6563 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006564 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006565 }
6566 }
6567 }
6568}
6569
6570static void
Owen Taylor3473f882001-02-23 17:55:21 +00006571xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006572 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006573 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006574 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006575 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006576
Owen Taylor3473f882001-02-23 17:55:21 +00006577 if (cur == NULL)
6578 return;
6579 switch (cur->atype) {
6580 case XML_ATTRIBUTE_CDATA:
6581 case XML_ATTRIBUTE_ID:
6582 case XML_ATTRIBUTE_IDREF :
6583 case XML_ATTRIBUTE_IDREFS:
6584 case XML_ATTRIBUTE_NMTOKEN:
6585 case XML_ATTRIBUTE_NMTOKENS:
6586 case XML_ATTRIBUTE_ENUMERATION:
6587 break;
6588 case XML_ATTRIBUTE_ENTITY:
6589 case XML_ATTRIBUTE_ENTITIES:
6590 case XML_ATTRIBUTE_NOTATION:
6591 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006592
6593 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6594 cur->atype, cur->defaultValue);
6595 if ((ret == 0) && (ctxt->valid == 1))
6596 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006597 }
6598 if (cur->tree != NULL) {
6599 xmlEnumerationPtr tree = cur->tree;
6600 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006601 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006602 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006603 if ((ret == 0) && (ctxt->valid == 1))
6604 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006605 tree = tree->next;
6606 }
6607 }
6608 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006609 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6610 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006611 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006612 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006613 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006614 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006615 return;
6616 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006617
6618 if (doc != NULL)
6619 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6620 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006621 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006622 if ((elem == NULL) && (cur->parent != NULL) &&
6623 (cur->parent->type == XML_DTD_NODE))
6624 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006625 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006626 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006627 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006628 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006629 return;
6630 }
6631 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006632 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006633 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006634 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006635 ctxt->valid = 0;
6636 }
6637 }
Owen Taylor3473f882001-02-23 17:55:21 +00006638}
6639
6640/**
6641 * xmlValidateDtdFinal:
6642 * @ctxt: the validation context
6643 * @doc: a document instance
6644 *
6645 * Does the final step for the dtds validation once all the
6646 * subsets have been parsed
6647 *
6648 * basically it does the following checks described by the XML Rec
6649 * - check that ENTITY and ENTITIES type attributes default or
6650 * possible values matches one of the defined entities.
6651 * - check that NOTATION type attributes default or
6652 * possible values matches one of the defined notations.
6653 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006654 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006655 */
6656
6657int
6658xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006659 xmlDtdPtr dtd;
6660 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006661 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006662
6663 if (doc == NULL) return(0);
6664 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6665 return(0);
6666 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006667 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006668 dtd = doc->intSubset;
6669 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6670 table = (xmlAttributeTablePtr) dtd->attributes;
6671 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006672 }
6673 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006674 entities = (xmlEntitiesTablePtr) dtd->entities;
6675 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6676 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006677 }
6678 dtd = doc->extSubset;
6679 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6680 table = (xmlAttributeTablePtr) dtd->attributes;
6681 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006682 }
6683 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006684 entities = (xmlEntitiesTablePtr) dtd->entities;
6685 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6686 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006687 }
6688 return(ctxt->valid);
6689}
6690
6691/**
6692 * xmlValidateDocument:
6693 * @ctxt: the validation context
6694 * @doc: a document instance
6695 *
6696 * Try to validate the document instance
6697 *
6698 * basically it does the all the checks described by the XML Rec
6699 * i.e. validates the internal and external subset (if present)
6700 * and validate the document tree.
6701 *
6702 * returns 1 if valid or 0 otherwise
6703 */
6704
6705int
6706xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6707 int ret;
6708 xmlNodePtr root;
6709
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006710 if (doc == NULL)
6711 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006712 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006713 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6714 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006715 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006716 }
Owen Taylor3473f882001-02-23 17:55:21 +00006717 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6718 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
William M. Brack8c22f9f2004-08-06 16:23:27 +00006719 xmlChar *sysID;
6720 if (doc->intSubset->SystemID != NULL) {
William M. Brackbebe7302004-08-05 06:46:47 +00006721 sysID = xmlBuildURI(doc->intSubset->SystemID,
6722 doc->URL);
William M. Brack8c22f9f2004-08-06 16:23:27 +00006723 if (sysID == NULL) {
6724 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6725 "Could not build URI for external subset \"%s\"\n",
6726 (const char *) doc->intSubset->SystemID);
6727 return 0;
6728 }
6729 } else
William M. Brackbebe7302004-08-05 06:46:47 +00006730 sysID = NULL;
William M. Brack8c22f9f2004-08-06 16:23:27 +00006731 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
William M. Brackbebe7302004-08-05 06:46:47 +00006732 (const xmlChar *)sysID);
William M. Brackbebe7302004-08-05 06:46:47 +00006733 if (sysID != NULL)
6734 xmlFree(sysID);
Owen Taylor3473f882001-02-23 17:55:21 +00006735 if (doc->extSubset == NULL) {
6736 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006737 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006738 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006739 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006740 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006741 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006742 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006743 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006744 }
6745 return(0);
6746 }
6747 }
6748
6749 if (doc->ids != NULL) {
6750 xmlFreeIDTable(doc->ids);
6751 doc->ids = NULL;
6752 }
6753 if (doc->refs != NULL) {
6754 xmlFreeRefTable(doc->refs);
6755 doc->refs = NULL;
6756 }
6757 ret = xmlValidateDtdFinal(ctxt, doc);
6758 if (!xmlValidateRoot(ctxt, doc)) return(0);
6759
6760 root = xmlDocGetRootElement(doc);
6761 ret &= xmlValidateElement(ctxt, doc, root);
6762 ret &= xmlValidateDocumentFinal(ctxt, doc);
6763 return(ret);
6764}
6765
Owen Taylor3473f882001-02-23 17:55:21 +00006766/************************************************************************
6767 * *
6768 * Routines for dynamic validation editing *
6769 * *
6770 ************************************************************************/
6771
6772/**
6773 * xmlValidGetPotentialChildren:
6774 * @ctree: an element content tree
Daniel Veillard7802ba52005-10-27 11:56:20 +00006775 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006776 * @len: a pointer to the number of element in the list
6777 * @max: the size of the array
6778 *
6779 * Build/extend a list of potential children allowed by the content tree
6780 *
6781 * returns the number of element in the list, or -1 in case of error.
6782 */
6783
6784int
Daniel Veillard7802ba52005-10-27 11:56:20 +00006785xmlValidGetPotentialChildren(xmlElementContent *ctree,
6786 const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006787 int *len, int max) {
6788 int i;
6789
Daniel Veillard7802ba52005-10-27 11:56:20 +00006790 if ((ctree == NULL) || (names == NULL) || (len == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006791 return(-1);
6792 if (*len >= max) return(*len);
6793
6794 switch (ctree->type) {
6795 case XML_ELEMENT_CONTENT_PCDATA:
6796 for (i = 0; i < *len;i++)
Daniel Veillard7802ba52005-10-27 11:56:20 +00006797 if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
6798 names[(*len)++] = BAD_CAST "#PCDATA";
Owen Taylor3473f882001-02-23 17:55:21 +00006799 break;
6800 case XML_ELEMENT_CONTENT_ELEMENT:
6801 for (i = 0; i < *len;i++)
Daniel Veillard7802ba52005-10-27 11:56:20 +00006802 if (xmlStrEqual(ctree->name, names[i])) return(*len);
6803 names[(*len)++] = ctree->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006804 break;
6805 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard7802ba52005-10-27 11:56:20 +00006806 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6807 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
Owen Taylor3473f882001-02-23 17:55:21 +00006808 break;
6809 case XML_ELEMENT_CONTENT_OR:
Daniel Veillard7802ba52005-10-27 11:56:20 +00006810 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6811 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
Owen Taylor3473f882001-02-23 17:55:21 +00006812 break;
6813 }
6814
6815 return(*len);
6816}
6817
William M. Brack9333cc22004-06-24 08:33:40 +00006818/*
6819 * Dummy function to suppress messages while we try out valid elements
6820 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00006821static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
William M. Brack9333cc22004-06-24 08:33:40 +00006822 const char *msg ATTRIBUTE_UNUSED, ...) {
6823 return;
6824}
6825
Owen Taylor3473f882001-02-23 17:55:21 +00006826/**
6827 * xmlValidGetValidElements:
6828 * @prev: an element to insert after
6829 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006830 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006831 * @max: the size of the array
6832 *
6833 * This function returns the list of authorized children to insert
6834 * within an existing tree while respecting the validity constraints
6835 * forced by the Dtd. The insertion point is defined using @prev and
6836 * @next in the following ways:
6837 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6838 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6839 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6840 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6841 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6842 *
6843 * pointers to the element names are inserted at the beginning of the array
6844 * and do not need to be freed.
6845 *
6846 * returns the number of element in the list, or -1 in case of error. If
6847 * the function returns the value @max the caller is invited to grow the
6848 * receiving array and retry.
6849 */
6850
6851int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006852xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006853 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006854 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006855 int nb_valid_elements = 0;
6856 const xmlChar *elements[256];
6857 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006858 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006859
6860 xmlNode *ref_node;
6861 xmlNode *parent;
6862 xmlNode *test_node;
6863
6864 xmlNode *prev_next;
6865 xmlNode *next_prev;
6866 xmlNode *parent_childs;
6867 xmlNode *parent_last;
6868
6869 xmlElement *element_desc;
6870
6871 if (prev == NULL && next == NULL)
6872 return(-1);
6873
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006874 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006875 if (max <= 0) return(-1);
6876
William M. Brack9333cc22004-06-24 08:33:40 +00006877 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6878 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6879
Owen Taylor3473f882001-02-23 17:55:21 +00006880 nb_valid_elements = 0;
6881 ref_node = prev ? prev : next;
6882 parent = ref_node->parent;
6883
6884 /*
6885 * Retrieves the parent element declaration
6886 */
6887 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6888 parent->name);
6889 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6890 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6891 parent->name);
6892 if (element_desc == NULL) return(-1);
6893
6894 /*
6895 * Do a backup of the current tree structure
6896 */
6897 prev_next = prev ? prev->next : NULL;
6898 next_prev = next ? next->prev : NULL;
6899 parent_childs = parent->children;
6900 parent_last = parent->last;
6901
6902 /*
6903 * Creates a dummy node and insert it into the tree
6904 */
Daniel Veillard95ddcd32004-10-26 21:53:55 +00006905 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006906 test_node->parent = parent;
6907 test_node->prev = prev;
6908 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006909 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006910
6911 if (prev) prev->next = test_node;
6912 else parent->children = test_node;
6913
6914 if (next) next->prev = test_node;
6915 else parent->last = test_node;
6916
6917 /*
6918 * Insert each potential child node and check if the parent is
6919 * still valid
6920 */
6921 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6922 elements, &nb_elements, 256);
6923
6924 for (i = 0;i < nb_elements;i++) {
6925 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006926 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006927 int j;
6928
6929 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006930 if (xmlStrEqual(elements[i], names[j])) break;
6931 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00006932 if (nb_valid_elements >= max) break;
6933 }
6934 }
6935
6936 /*
6937 * Restore the tree structure
6938 */
6939 if (prev) prev->next = prev_next;
6940 if (next) next->prev = next_prev;
6941 parent->children = parent_childs;
6942 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006943
6944 /*
6945 * Free up the dummy node
6946 */
6947 test_node->name = name;
6948 xmlFreeNode(test_node);
6949
Owen Taylor3473f882001-02-23 17:55:21 +00006950 return(nb_valid_elements);
6951}
Daniel Veillard4432df22003-09-28 18:58:27 +00006952#endif /* LIBXML_VALID_ENABLED */
6953
Daniel Veillard5d4644e2005-04-01 13:11:58 +00006954#define bottom_valid
6955#include "elfgcchack.h"