blob: edf5426125a0029f2cfee47bc58eee8211f6c14d [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)) {
66 pctxt = ctxt->userData;
67 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +000068 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000069 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000070 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000071 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000072 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
73 "Memory allocation failed : %s\n", extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000074 else
Daniel Veillard73000572003-10-11 11:26:42 +000075 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000076 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000077 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
78 "Memory allocation failed\n");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000079}
80
81/**
82 * xmlErrValid:
83 * @ctxt: an XML validation parser context
Daniel Veillardbb5abab2003-10-03 22:21:51 +000084 * @error: the error number
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000085 * @extra: extra informations
86 *
87 * Handle a validation error
88 */
89static void
Daniel Veillardf88d8cf2003-12-08 10:25:02 +000090xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000091 const char *msg, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000092{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000093 xmlGenericErrorFunc channel = NULL;
94 xmlParserCtxtPtr pctxt = NULL;
95 void *data = NULL;
96
97 if (ctxt != NULL) {
98 channel = ctxt->error;
99 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000100 /* Use the special values to detect if it is part of a parsing
101 context */
102 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
103 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
104 pctxt = ctxt->userData;
105 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000106 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000107 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +0000108 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000109 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000110 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
111 msg, extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000112 else
Daniel Veillard73000572003-10-11 11:26:42 +0000113 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000114 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000115 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
116 msg);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000117}
118
Daniel Veillardf54cd532004-02-25 11:52:31 +0000119#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
120/**
121 * xmlErrValidNode:
122 * @ctxt: an XML validation parser context
123 * @node: the node raising the error
124 * @error: the error number
125 * @str1: extra informations
126 * @str2: extra informations
127 * @str3: extra informations
128 *
129 * Handle a validation error, provide contextual informations
130 */
131static void
132xmlErrValidNode(xmlValidCtxtPtr ctxt,
133 xmlNodePtr node, xmlParserErrors error,
134 const char *msg, const xmlChar * str1,
135 const xmlChar * str2, const xmlChar * str3)
136{
137 xmlStructuredErrorFunc schannel = NULL;
138 xmlGenericErrorFunc channel = NULL;
139 xmlParserCtxtPtr pctxt = NULL;
140 void *data = NULL;
141
142 if (ctxt != NULL) {
143 channel = ctxt->error;
144 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000145 /* Use the special values to detect if it is part of a parsing
146 context */
147 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
148 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
149 pctxt = ctxt->userData;
150 }
Daniel Veillardf54cd532004-02-25 11:52:31 +0000151 }
152 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
153 XML_ERR_ERROR, NULL, 0,
154 (const char *) str1,
155 (const char *) str1,
156 (const char *) str3, 0, 0, msg, str1, str2, str3);
157}
158#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
159
Daniel Veillardd61e8fb2003-10-19 21:59:17 +0000160#ifdef LIBXML_VALID_ENABLED
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000161/**
162 * xmlErrValidNodeNr:
163 * @ctxt: an XML validation parser context
164 * @node: the node raising the error
165 * @error: the error number
166 * @str1: extra informations
167 * @int2: extra informations
168 * @str3: extra informations
169 *
170 * Handle a validation error, provide contextual informations
171 */
172static void
Daniel Veillard72b9e292003-10-28 15:44:17 +0000173xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000174 xmlNodePtr node, xmlParserErrors error,
175 const char *msg, const xmlChar * str1,
176 int int2, const xmlChar * str3)
177{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000178 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000179 xmlGenericErrorFunc channel = NULL;
180 xmlParserCtxtPtr pctxt = NULL;
181 void *data = NULL;
182
183 if (ctxt != NULL) {
184 channel = ctxt->error;
185 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000186 /* Use the special values to detect if it is part of a parsing
187 context */
188 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
189 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
190 pctxt = ctxt->userData;
191 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000192 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000193 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000194 XML_ERR_ERROR, NULL, 0,
195 (const char *) str1,
196 (const char *) str3,
197 NULL, int2, 0, msg, str1, int2, str3);
198}
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000199
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000200/**
201 * xmlErrValidWarning:
202 * @ctxt: an XML validation parser context
203 * @node: the node raising the error
204 * @error: the error number
William M. Brackedb65a72004-02-06 07:36:04 +0000205 * @str1: extra information
206 * @str2: extra information
207 * @str3: extra information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000208 *
William M. Brackedb65a72004-02-06 07:36:04 +0000209 * Handle a validation error, provide contextual information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000210 */
211static void
William M. Brackedb65a72004-02-06 07:36:04 +0000212xmlErrValidWarning(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000213 xmlNodePtr node, xmlParserErrors error,
214 const char *msg, const xmlChar * str1,
215 const xmlChar * str2, const xmlChar * str3)
216{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000217 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000218 xmlGenericErrorFunc channel = NULL;
219 xmlParserCtxtPtr pctxt = NULL;
220 void *data = NULL;
221
222 if (ctxt != NULL) {
William M. Bracke4d526f2004-12-18 00:01:21 +0000223 channel = ctxt->warning;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000224 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000225 /* Use the special values to detect if it is part of a parsing
226 context */
227 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
228 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
229 pctxt = ctxt->userData;
230 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000231 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000232 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000233 XML_ERR_WARNING, NULL, 0,
234 (const char *) str1,
235 (const char *) str1,
236 (const char *) str3, 0, 0, msg, str1, str2, str3);
237}
238
239
Daniel Veillardea7751d2002-12-20 00:16:24 +0000240
241#ifdef LIBXML_REGEXP_ENABLED
242/*
243 * If regexp are enabled we can do continuous validation without the
244 * need of a tree to validate the content model. this is done in each
245 * callbacks.
246 * Each xmlValidState represent the validation state associated to the
247 * set of nodes currently open from the document root to the current element.
248 */
249
250
251typedef struct _xmlValidState {
252 xmlElementPtr elemDecl; /* pointer to the content model */
253 xmlNodePtr node; /* pointer to the current node */
254 xmlRegExecCtxtPtr exec; /* regexp runtime */
255} _xmlValidState;
256
257
258static int
259vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000260 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000261 ctxt->vstateMax = 10;
262 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
263 sizeof(ctxt->vstateTab[0]));
264 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000265 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000266 return(-1);
267 }
268 }
269
270 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000271 xmlValidState *tmp;
272
273 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
274 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
275 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000276 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000277 return(-1);
278 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000279 ctxt->vstateMax *= 2;
280 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000281 }
282 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
283 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
284 ctxt->vstateTab[ctxt->vstateNr].node = node;
285 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
286 if (elemDecl->contModel == NULL)
287 xmlValidBuildContentModel(ctxt, elemDecl);
288 if (elemDecl->contModel != NULL) {
289 ctxt->vstateTab[ctxt->vstateNr].exec =
290 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
291 } else {
292 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000293 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
294 XML_ERR_INTERNAL_ERROR,
295 "Failed to build content model regexp for %s\n",
296 node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000297 }
298 }
299 return(ctxt->vstateNr++);
300}
301
302static int
303vstateVPop(xmlValidCtxtPtr ctxt) {
304 xmlElementPtr elemDecl;
305
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000306 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000307 ctxt->vstateNr--;
308 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
309 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
310 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
311 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
312 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
313 }
314 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
315 if (ctxt->vstateNr >= 1)
316 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
317 else
318 ctxt->vstate = NULL;
319 return(ctxt->vstateNr);
320}
321
322#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000323/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000324 * If regexp are not enabled, it uses a home made algorithm less
325 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000326 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000327 * only restriction is on the deepness of the tree limited by the
328 * size of the occurs bitfield
329 *
330 * this is the content of a saved state for rollbacks
331 */
332
333#define ROLLBACK_OR 0
334#define ROLLBACK_PARENT 1
335
Daniel Veillardb44025c2001-10-11 22:55:55 +0000336typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000337 xmlElementContentPtr cont; /* pointer to the content model subtree */
338 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000339 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000340 unsigned char depth; /* current depth in the overall tree */
341 unsigned char state; /* ROLLBACK_XXX */
342} _xmlValidState;
343
Daniel Veillardfc57b412002-04-29 15:50:14 +0000344#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000345#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
346#define CONT ctxt->vstate->cont
347#define NODE ctxt->vstate->node
348#define DEPTH ctxt->vstate->depth
349#define OCCURS ctxt->vstate->occurs
350#define STATE ctxt->vstate->state
351
Daniel Veillard5344c602001-12-31 16:37:34 +0000352#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
353#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000354
Daniel Veillard5344c602001-12-31 16:37:34 +0000355#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
356#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000357
358static int
359vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
360 xmlNodePtr node, unsigned char depth, long occurs,
361 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000362 int i = ctxt->vstateNr - 1;
363
Daniel Veillard940492d2002-04-15 10:15:25 +0000364 if (ctxt->vstateNr > MAX_RECURSE) {
365 return(-1);
366 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000367 if (ctxt->vstateTab == NULL) {
368 ctxt->vstateMax = 8;
369 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
370 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
371 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000372 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000373 return(-1);
374 }
375 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000376 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000377 xmlValidState *tmp;
378
379 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
380 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
381 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000382 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000383 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000384 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000385 ctxt->vstateMax *= 2;
386 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000387 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000388 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000389 /*
390 * Don't push on the stack a state already here
391 */
392 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
393 (ctxt->vstateTab[i].node == node) &&
394 (ctxt->vstateTab[i].depth == depth) &&
395 (ctxt->vstateTab[i].occurs == occurs) &&
396 (ctxt->vstateTab[i].state == state))
397 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000398 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
399 ctxt->vstateTab[ctxt->vstateNr].node = node;
400 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
401 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
402 ctxt->vstateTab[ctxt->vstateNr].state = state;
403 return(ctxt->vstateNr++);
404}
405
406static int
407vstateVPop(xmlValidCtxtPtr ctxt) {
408 if (ctxt->vstateNr <= 1) return(-1);
409 ctxt->vstateNr--;
410 ctxt->vstate = &ctxt->vstateTab[0];
411 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
412 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
413 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
414 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
415 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
416 return(ctxt->vstateNr);
417}
418
Daniel Veillard118aed72002-09-24 14:13:13 +0000419#endif /* LIBXML_REGEXP_ENABLED */
420
Daniel Veillard1c732d22002-11-30 11:22:59 +0000421static int
422nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
423{
424 if (ctxt->nodeMax <= 0) {
425 ctxt->nodeMax = 4;
426 ctxt->nodeTab =
427 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
428 sizeof(ctxt->nodeTab[0]));
429 if (ctxt->nodeTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000430 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000431 ctxt->nodeMax = 0;
432 return (0);
433 }
434 }
435 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000436 xmlNodePtr *tmp;
437 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
438 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
439 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000440 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000441 return (0);
442 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000443 ctxt->nodeMax *= 2;
444 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000445 }
446 ctxt->nodeTab[ctxt->nodeNr] = value;
447 ctxt->node = value;
448 return (ctxt->nodeNr++);
449}
450static xmlNodePtr
451nodeVPop(xmlValidCtxtPtr ctxt)
452{
453 xmlNodePtr ret;
454
455 if (ctxt->nodeNr <= 0)
Daniel Veillard24505b02005-07-28 23:49:35 +0000456 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +0000457 ctxt->nodeNr--;
458 if (ctxt->nodeNr > 0)
459 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
460 else
461 ctxt->node = NULL;
462 ret = ctxt->nodeTab[ctxt->nodeNr];
Daniel Veillard24505b02005-07-28 23:49:35 +0000463 ctxt->nodeTab[ctxt->nodeNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000464 return (ret);
465}
Owen Taylor3473f882001-02-23 17:55:21 +0000466
Owen Taylor3473f882001-02-23 17:55:21 +0000467#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000468static void
469xmlValidPrintNode(xmlNodePtr cur) {
470 if (cur == NULL) {
471 xmlGenericError(xmlGenericErrorContext, "null");
472 return;
473 }
474 switch (cur->type) {
475 case XML_ELEMENT_NODE:
476 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
477 break;
478 case XML_TEXT_NODE:
479 xmlGenericError(xmlGenericErrorContext, "text ");
480 break;
481 case XML_CDATA_SECTION_NODE:
482 xmlGenericError(xmlGenericErrorContext, "cdata ");
483 break;
484 case XML_ENTITY_REF_NODE:
485 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
486 break;
487 case XML_PI_NODE:
488 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
489 break;
490 case XML_COMMENT_NODE:
491 xmlGenericError(xmlGenericErrorContext, "comment ");
492 break;
493 case XML_ATTRIBUTE_NODE:
494 xmlGenericError(xmlGenericErrorContext, "?attr? ");
495 break;
496 case XML_ENTITY_NODE:
497 xmlGenericError(xmlGenericErrorContext, "?ent? ");
498 break;
499 case XML_DOCUMENT_NODE:
500 xmlGenericError(xmlGenericErrorContext, "?doc? ");
501 break;
502 case XML_DOCUMENT_TYPE_NODE:
503 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
504 break;
505 case XML_DOCUMENT_FRAG_NODE:
506 xmlGenericError(xmlGenericErrorContext, "?frag? ");
507 break;
508 case XML_NOTATION_NODE:
509 xmlGenericError(xmlGenericErrorContext, "?nota? ");
510 break;
511 case XML_HTML_DOCUMENT_NODE:
512 xmlGenericError(xmlGenericErrorContext, "?html? ");
513 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000514#ifdef LIBXML_DOCB_ENABLED
515 case XML_DOCB_DOCUMENT_NODE:
516 xmlGenericError(xmlGenericErrorContext, "?docb? ");
517 break;
518#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000519 case XML_DTD_NODE:
520 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
521 break;
522 case XML_ELEMENT_DECL:
523 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
524 break;
525 case XML_ATTRIBUTE_DECL:
526 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
527 break;
528 case XML_ENTITY_DECL:
529 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
530 break;
531 case XML_NAMESPACE_DECL:
532 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
533 break;
534 case XML_XINCLUDE_START:
535 xmlGenericError(xmlGenericErrorContext, "incstart ");
536 break;
537 case XML_XINCLUDE_END:
538 xmlGenericError(xmlGenericErrorContext, "incend ");
539 break;
540 }
541}
542
543static void
544xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000545 if (cur == NULL)
546 xmlGenericError(xmlGenericErrorContext, "null ");
547 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000548 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000549 cur = cur->next;
550 }
551}
552
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000553static void
554xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000555 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000556
557 expr[0] = 0;
558 xmlGenericError(xmlGenericErrorContext, "valid: ");
559 xmlValidPrintNodeList(cur);
560 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000561 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000562 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
563}
564
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000565static void
566xmlValidDebugState(xmlValidStatePtr state) {
567 xmlGenericError(xmlGenericErrorContext, "(");
568 if (state->cont == NULL)
569 xmlGenericError(xmlGenericErrorContext, "null,");
570 else
571 switch (state->cont->type) {
572 case XML_ELEMENT_CONTENT_PCDATA:
573 xmlGenericError(xmlGenericErrorContext, "pcdata,");
574 break;
575 case XML_ELEMENT_CONTENT_ELEMENT:
576 xmlGenericError(xmlGenericErrorContext, "%s,",
577 state->cont->name);
578 break;
579 case XML_ELEMENT_CONTENT_SEQ:
580 xmlGenericError(xmlGenericErrorContext, "seq,");
581 break;
582 case XML_ELEMENT_CONTENT_OR:
583 xmlGenericError(xmlGenericErrorContext, "or,");
584 break;
585 }
586 xmlValidPrintNode(state->node);
587 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
588 state->depth, state->occurs, state->state);
589}
590
591static void
592xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
593 int i, j;
594
595 xmlGenericError(xmlGenericErrorContext, "state: ");
596 xmlValidDebugState(ctxt->vstate);
597 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
598 ctxt->vstateNr - 1);
599 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
600 xmlValidDebugState(&ctxt->vstateTab[j]);
601 xmlGenericError(xmlGenericErrorContext, "\n");
602}
603
604/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000605#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000606 *****/
607
608#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000609#define DEBUG_VALID_MSG(m) \
610 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
611
Owen Taylor3473f882001-02-23 17:55:21 +0000612#else
613#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000614#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000615#endif
616
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000617/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000618
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000619
Owen Taylor3473f882001-02-23 17:55:21 +0000620#define CHECK_DTD \
621 if (doc == NULL) return(0); \
622 else if ((doc->intSubset == NULL) && \
623 (doc->extSubset == NULL)) return(0)
624
Owen Taylor3473f882001-02-23 17:55:21 +0000625xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
626
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000627#ifdef LIBXML_REGEXP_ENABLED
628
629/************************************************************************
630 * *
631 * Content model validation based on the regexps *
632 * *
633 ************************************************************************/
634
635/**
636 * xmlValidBuildAContentModel:
637 * @content: the content model
638 * @ctxt: the schema parser context
639 * @name: the element name whose content is being built
640 *
641 * Generate the automata sequence needed for that type
642 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000643 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000644 */
645static int
646xmlValidBuildAContentModel(xmlElementContentPtr content,
647 xmlValidCtxtPtr ctxt,
648 const xmlChar *name) {
649 if (content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000650 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
651 "Found NULL content in content model of %s\n",
652 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000653 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000654 }
655 switch (content->type) {
656 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000657 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
658 "Found PCDATA in content model of %s\n",
659 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000660 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000661 break;
662 case XML_ELEMENT_CONTENT_ELEMENT: {
663 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000664 xmlChar fn[50];
665 xmlChar *fullname;
666
667 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
668 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000669 xmlVErrMemory(ctxt, "Building content model");
Daniel Veillardc00cda82003-04-07 10:22:39 +0000670 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000671 }
672
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000673 switch (content->ocur) {
674 case XML_ELEMENT_CONTENT_ONCE:
675 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000676 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000677 break;
678 case XML_ELEMENT_CONTENT_OPT:
679 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000680 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000681 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
682 break;
683 case XML_ELEMENT_CONTENT_PLUS:
684 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000685 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000686 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000687 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000688 break;
689 case XML_ELEMENT_CONTENT_MULT:
William M. Brack8b0cbb02004-04-17 13:31:06 +0000690 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
691 ctxt->state, NULL);
692 xmlAutomataNewTransition(ctxt->am,
693 ctxt->state, ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000694 break;
695 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000696 if ((fullname != fn) && (fullname != content->name))
697 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000698 break;
699 }
700 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000701 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000702 xmlElementContentOccur ocur;
703
704 /*
705 * Simply iterate over the content
706 */
707 oldstate = ctxt->state;
708 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000709 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
710 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
711 oldstate = ctxt->state;
712 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000713 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000714 xmlValidBuildAContentModel(content->c1, ctxt, name);
715 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000716 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
717 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
718 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000719 oldend = ctxt->state;
720 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000721 switch (ocur) {
722 case XML_ELEMENT_CONTENT_ONCE:
723 break;
724 case XML_ELEMENT_CONTENT_OPT:
725 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
726 break;
727 case XML_ELEMENT_CONTENT_MULT:
728 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000729 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000730 break;
731 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000732 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000733 break;
734 }
735 break;
736 }
737 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000738 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000739 xmlElementContentOccur ocur;
740
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000741 ocur = content->ocur;
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000742 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
743 (ocur == XML_ELEMENT_CONTENT_MULT)) {
744 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
745 ctxt->state, NULL);
746 }
747 oldstate = ctxt->state;
748 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000749
750 /*
751 * iterate over the subtypes and remerge the end with an
752 * epsilon transition
753 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000754 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000755 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000756 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000757 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000758 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000759 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
760 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000761 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000762 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000763 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
764 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000765 switch (ocur) {
766 case XML_ELEMENT_CONTENT_ONCE:
767 break;
768 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000769 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000770 break;
771 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000772 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
773 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000774 break;
775 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000776 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000777 break;
778 }
779 break;
780 }
781 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000782 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
783 "ContentModel broken for element %s\n",
784 (const char *) name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000785 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000786 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000787 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000788}
789/**
790 * xmlValidBuildContentModel:
791 * @ctxt: a validation context
792 * @elem: an element declaration node
793 *
794 * (Re)Build the automata associated to the content model of this
795 * element
796 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000797 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000798 */
799int
800xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000801
802 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000803 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000804 if (elem->type != XML_ELEMENT_DECL)
805 return(0);
806 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
807 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000808 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000809 if (elem->contModel != NULL) {
810 if (!xmlRegexpIsDeterminist(elem->contModel)) {
811 ctxt->valid = 0;
812 return(0);
813 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000814 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000815 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000816
817 ctxt->am = xmlNewAutomata();
818 if (ctxt->am == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000819 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
820 XML_ERR_INTERNAL_ERROR,
821 "Cannot create automata for element %s\n",
822 elem->name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000823 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000824 }
William M. Brack78637da2003-07-31 14:47:38 +0000825 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000826 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
827 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000828 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000829 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000830 char expr[5000];
831 expr[0] = 0;
832 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000833 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
834 XML_DTD_CONTENT_NOT_DETERMINIST,
835 "Content model of %s is not determinist: %s\n",
836 elem->name, BAD_CAST expr, NULL);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000837#ifdef DEBUG_REGEXP_ALGO
838 xmlRegexpPrint(stderr, elem->contModel);
839#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000840 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000841 ctxt->state = NULL;
842 xmlFreeAutomata(ctxt->am);
843 ctxt->am = NULL;
844 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000845 }
846 ctxt->state = NULL;
847 xmlFreeAutomata(ctxt->am);
848 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000849 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000850}
851
852#endif /* LIBXML_REGEXP_ENABLED */
853
Owen Taylor3473f882001-02-23 17:55:21 +0000854/****************************************************************
855 * *
856 * Util functions for data allocation/deallocation *
857 * *
858 ****************************************************************/
859
860/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000861 * xmlNewValidCtxt:
862 *
863 * Allocate a validation context structure.
864 *
865 * Returns NULL if not, otherwise the new validation context structure
866 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000867xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000868 xmlValidCtxtPtr ret;
869
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000870 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000871 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000872 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000873 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000874
875 (void) memset(ret, 0, sizeof (xmlValidCtxt));
876
877 return (ret);
878}
879
880/**
881 * xmlFreeValidCtxt:
882 * @cur: the validation context to free
883 *
884 * Free a validation context structure.
885 */
886void
887xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
Daniel Veillardc0be74b2004-11-03 19:16:55 +0000888 if (cur->vstateTab != NULL)
889 xmlFree(cur->vstateTab);
890 if (cur->nodeTab != NULL)
891 xmlFree(cur->nodeTab);
Daniel Veillarda37aab82003-06-09 09:10:36 +0000892 xmlFree(cur);
893}
894
Daniel Veillard4432df22003-09-28 18:58:27 +0000895#endif /* LIBXML_VALID_ENABLED */
896
Daniel Veillarda37aab82003-06-09 09:10:36 +0000897/**
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000898 * xmlNewDocElementContent:
899 * @doc: the document
Owen Taylor3473f882001-02-23 17:55:21 +0000900 * @name: the subelement name or NULL
901 * @type: the type of element content decl
902 *
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000903 * Allocate an element content structure for the document.
Owen Taylor3473f882001-02-23 17:55:21 +0000904 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000905 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000906 */
907xmlElementContentPtr
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000908xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
909 xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000910 xmlElementContentPtr ret;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000911 xmlDictPtr dict = NULL;
912
913 if (doc != NULL)
914 dict = doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +0000915
916 switch(type) {
917 case XML_ELEMENT_CONTENT_ELEMENT:
918 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000919 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
920 "xmlNewElementContent : name == NULL !\n",
921 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000922 }
923 break;
924 case XML_ELEMENT_CONTENT_PCDATA:
925 case XML_ELEMENT_CONTENT_SEQ:
926 case XML_ELEMENT_CONTENT_OR:
927 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000928 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
929 "xmlNewElementContent : name != NULL !\n",
930 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000931 }
932 break;
933 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000934 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
935 "Internal: ELEMENT content corrupted invalid type\n",
936 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000937 return(NULL);
938 }
939 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
940 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000941 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000942 return(NULL);
943 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000944 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000945 ret->type = type;
946 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000947 if (name != NULL) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000948 int l;
949 const xmlChar *tmp;
950
951 tmp = xmlSplitQName3(name, &l);
952 if (tmp == NULL) {
953 if (dict == NULL)
954 ret->name = xmlStrdup(name);
955 else
956 ret->name = xmlDictLookup(dict, name, -1);
957 } else {
958 if (dict == NULL) {
959 ret->prefix = xmlStrndup(name, l);
960 ret->name = xmlStrdup(tmp);
961 } else {
962 ret->prefix = xmlDictLookup(dict, name, l);
963 ret->name = xmlDictLookup(dict, tmp, -1);
964 }
965 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000966 }
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000967 return(ret);
968}
969
970/**
971 * xmlNewElementContent:
972 * @name: the subelement name or NULL
973 * @type: the type of element content decl
974 *
975 * Allocate an element content structure.
976 * Deprecated in favor of xmlNewDocElementContent
977 *
978 * Returns NULL if not, otherwise the new element content structure
979 */
980xmlElementContentPtr
981xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
982 return(xmlNewDocElementContent(NULL, name, type));
983}
984
985/**
986 * xmlCopyDocElementContent:
987 * @doc: the document owning the element declaration
988 * @cur: An element content pointer.
989 *
990 * Build a copy of an element content description.
991 *
992 * Returns the new xmlElementContentPtr or NULL in case of error.
993 */
994xmlElementContentPtr
995xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
996 xmlElementContentPtr ret = NULL, prev = NULL, tmp;
997 xmlDictPtr dict = NULL;
998
999 if (cur == NULL) return(NULL);
1000
1001 if (doc != NULL)
1002 dict = doc->dict;
1003
1004 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1005 if (ret == NULL) {
1006 xmlVErrMemory(NULL, "malloc failed");
1007 return(NULL);
1008 }
1009 memset(ret, 0, sizeof(xmlElementContent));
1010 ret->type = cur->type;
1011 ret->ocur = cur->ocur;
1012 if (cur->name != NULL) {
1013 if (dict)
1014 ret->name = xmlDictLookup(dict, cur->name, -1);
1015 else
1016 ret->name = xmlStrdup(cur->name);
1017 }
1018
1019 if (cur->prefix != NULL) {
1020 if (dict)
1021 ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1022 else
1023 ret->prefix = xmlStrdup(cur->prefix);
1024 }
1025 if (cur->c1 != NULL)
1026 ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1027 if (ret->c1 != NULL)
1028 ret->c1->parent = ret;
1029 if (cur->c2 != NULL) {
1030 prev = ret;
1031 cur = cur->c2;
1032 while (cur != NULL) {
1033 tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1034 if (tmp == NULL) {
1035 xmlVErrMemory(NULL, "malloc failed");
1036 return(ret);
1037 }
1038 memset(tmp, 0, sizeof(xmlElementContent));
1039 tmp->type = cur->type;
1040 tmp->ocur = cur->ocur;
1041 prev->c2 = tmp;
1042 if (cur->name != NULL) {
1043 if (dict)
1044 tmp->name = xmlDictLookup(dict, cur->name, -1);
1045 else
1046 tmp->name = xmlStrdup(cur->name);
1047 }
1048
1049 if (cur->prefix != NULL) {
1050 if (dict)
1051 tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1052 else
1053 tmp->prefix = xmlStrdup(cur->prefix);
1054 }
1055 if (cur->c1 != NULL)
1056 tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1057 if (tmp->c1 != NULL)
1058 tmp->c1->parent = ret;
1059 prev = tmp;
1060 cur = cur->c2;
1061 }
1062 }
Owen Taylor3473f882001-02-23 17:55:21 +00001063 return(ret);
1064}
1065
1066/**
1067 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +00001068 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +00001069 *
1070 * Build a copy of an element content description.
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001071 * Deprecated, use xmlCopyDocElementContent instead
Owen Taylor3473f882001-02-23 17:55:21 +00001072 *
1073 * Returns the new xmlElementContentPtr or NULL in case of error.
1074 */
1075xmlElementContentPtr
1076xmlCopyElementContent(xmlElementContentPtr cur) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001077 return(xmlCopyDocElementContent(NULL, cur));
1078}
Owen Taylor3473f882001-02-23 17:55:21 +00001079
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001080/**
1081 * xmlFreeDocElementContent:
1082 * @doc: the document owning the element declaration
1083 * @cur: the element content tree to free
1084 *
1085 * Free an element content structure. The whole subtree is removed.
1086 */
1087void
1088xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1089 xmlElementContentPtr next;
1090 xmlDictPtr dict = NULL;
1091
1092 if (doc != NULL)
1093 dict = doc->dict;
1094
1095 while (cur != NULL) {
1096 next = cur->c2;
1097 switch (cur->type) {
1098 case XML_ELEMENT_CONTENT_PCDATA:
1099 case XML_ELEMENT_CONTENT_ELEMENT:
1100 case XML_ELEMENT_CONTENT_SEQ:
1101 case XML_ELEMENT_CONTENT_OR:
1102 break;
1103 default:
1104 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1105 "Internal: ELEMENT content corrupted invalid type\n",
1106 NULL);
1107 return;
1108 }
1109 if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1);
1110 if (dict) {
1111 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1112 xmlFree((xmlChar *) cur->name);
1113 if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1114 xmlFree((xmlChar *) cur->prefix);
1115 } else {
1116 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1117 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1118 }
1119 xmlFree(cur);
1120 cur = next;
Owen Taylor3473f882001-02-23 17:55:21 +00001121 }
Owen Taylor3473f882001-02-23 17:55:21 +00001122}
1123
1124/**
1125 * xmlFreeElementContent:
1126 * @cur: the element content tree to free
1127 *
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001128 * Free an element content structure. The whole subtree is removed.
1129 * Deprecated, use xmlFreeDocElementContent instead
Owen Taylor3473f882001-02-23 17:55:21 +00001130 */
1131void
1132xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001133 xmlFreeDocElementContent(NULL, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001134}
1135
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001136#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001137/**
1138 * xmlDumpElementContent:
1139 * @buf: An XML buffer
1140 * @content: An element table
1141 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1142 *
1143 * This will dump the content of the element table as an XML DTD definition
1144 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001145static void
Owen Taylor3473f882001-02-23 17:55:21 +00001146xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1147 if (content == NULL) return;
1148
1149 if (glob) xmlBufferWriteChar(buf, "(");
1150 switch (content->type) {
1151 case XML_ELEMENT_CONTENT_PCDATA:
1152 xmlBufferWriteChar(buf, "#PCDATA");
1153 break;
1154 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001155 if (content->prefix != NULL) {
1156 xmlBufferWriteCHAR(buf, content->prefix);
1157 xmlBufferWriteChar(buf, ":");
1158 }
Owen Taylor3473f882001-02-23 17:55:21 +00001159 xmlBufferWriteCHAR(buf, content->name);
1160 break;
1161 case XML_ELEMENT_CONTENT_SEQ:
1162 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1163 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1164 xmlDumpElementContent(buf, content->c1, 1);
1165 else
1166 xmlDumpElementContent(buf, content->c1, 0);
1167 xmlBufferWriteChar(buf, " , ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001168 if ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1169 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
1170 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001171 xmlDumpElementContent(buf, content->c2, 1);
1172 else
1173 xmlDumpElementContent(buf, content->c2, 0);
1174 break;
1175 case XML_ELEMENT_CONTENT_OR:
1176 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1177 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1178 xmlDumpElementContent(buf, content->c1, 1);
1179 else
1180 xmlDumpElementContent(buf, content->c1, 0);
1181 xmlBufferWriteChar(buf, " | ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001182 if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1183 ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
1184 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001185 xmlDumpElementContent(buf, content->c2, 1);
1186 else
1187 xmlDumpElementContent(buf, content->c2, 0);
1188 break;
1189 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001190 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1191 "Internal: ELEMENT content corrupted invalid type\n",
1192 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001193 }
1194 if (glob)
1195 xmlBufferWriteChar(buf, ")");
1196 switch (content->ocur) {
1197 case XML_ELEMENT_CONTENT_ONCE:
1198 break;
1199 case XML_ELEMENT_CONTENT_OPT:
1200 xmlBufferWriteChar(buf, "?");
1201 break;
1202 case XML_ELEMENT_CONTENT_MULT:
1203 xmlBufferWriteChar(buf, "*");
1204 break;
1205 case XML_ELEMENT_CONTENT_PLUS:
1206 xmlBufferWriteChar(buf, "+");
1207 break;
1208 }
1209}
1210
1211/**
1212 * xmlSprintfElementContent:
1213 * @buf: an output buffer
1214 * @content: An element table
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001215 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001216 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001217 * Deprecated, unsafe, use xmlSnprintfElementContent
1218 */
1219void
1220xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1221 xmlElementContentPtr content ATTRIBUTE_UNUSED,
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001222 int englob ATTRIBUTE_UNUSED) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001223}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001224#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001225
1226/**
1227 * xmlSnprintfElementContent:
1228 * @buf: an output buffer
1229 * @size: the buffer size
1230 * @content: An element table
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001231 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
Daniel Veillardd3d06722001-08-15 12:06:36 +00001232 *
Owen Taylor3473f882001-02-23 17:55:21 +00001233 * This will dump the content of the element content definition
1234 * Intended just for the debug routine
1235 */
1236void
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001237xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001238 int len;
1239
Owen Taylor3473f882001-02-23 17:55:21 +00001240 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001241 len = strlen(buf);
1242 if (size - len < 50) {
1243 if ((size - len > 4) && (buf[len - 1] != '.'))
1244 strcat(buf, " ...");
1245 return;
1246 }
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001247 if (englob) strcat(buf, "(");
Owen Taylor3473f882001-02-23 17:55:21 +00001248 switch (content->type) {
1249 case XML_ELEMENT_CONTENT_PCDATA:
1250 strcat(buf, "#PCDATA");
1251 break;
1252 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001253 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001254 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001255 strcat(buf, " ...");
1256 return;
1257 }
1258 strcat(buf, (char *) content->prefix);
1259 strcat(buf, ":");
1260 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001261 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001262 strcat(buf, " ...");
1263 return;
1264 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001265 if (content->name != NULL)
1266 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001267 break;
1268 case XML_ELEMENT_CONTENT_SEQ:
1269 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1270 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001271 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001272 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001273 xmlSnprintfElementContent(buf, size, content->c1, 0);
1274 len = strlen(buf);
1275 if (size - len < 50) {
1276 if ((size - len > 4) && (buf[len - 1] != '.'))
1277 strcat(buf, " ...");
1278 return;
1279 }
Owen Taylor3473f882001-02-23 17:55:21 +00001280 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001281 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1282 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1283 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001284 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001285 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001286 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001287 break;
1288 case XML_ELEMENT_CONTENT_OR:
1289 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1290 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001291 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001292 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001293 xmlSnprintfElementContent(buf, size, content->c1, 0);
1294 len = strlen(buf);
1295 if (size - len < 50) {
1296 if ((size - len > 4) && (buf[len - 1] != '.'))
1297 strcat(buf, " ...");
1298 return;
1299 }
Owen Taylor3473f882001-02-23 17:55:21 +00001300 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001301 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1302 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1303 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001304 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001305 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001306 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001307 break;
1308 }
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001309 if (englob)
Owen Taylor3473f882001-02-23 17:55:21 +00001310 strcat(buf, ")");
1311 switch (content->ocur) {
1312 case XML_ELEMENT_CONTENT_ONCE:
1313 break;
1314 case XML_ELEMENT_CONTENT_OPT:
1315 strcat(buf, "?");
1316 break;
1317 case XML_ELEMENT_CONTENT_MULT:
1318 strcat(buf, "*");
1319 break;
1320 case XML_ELEMENT_CONTENT_PLUS:
1321 strcat(buf, "+");
1322 break;
1323 }
1324}
1325
1326/****************************************************************
1327 * *
1328 * Registration of DTD declarations *
1329 * *
1330 ****************************************************************/
1331
1332/**
Owen Taylor3473f882001-02-23 17:55:21 +00001333 * xmlFreeElement:
1334 * @elem: An element
1335 *
1336 * Deallocate the memory used by an element definition
1337 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001338static void
Owen Taylor3473f882001-02-23 17:55:21 +00001339xmlFreeElement(xmlElementPtr elem) {
1340 if (elem == NULL) return;
1341 xmlUnlinkNode((xmlNodePtr) elem);
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001342 xmlFreeDocElementContent(elem->doc, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001343 if (elem->name != NULL)
1344 xmlFree((xmlChar *) elem->name);
1345 if (elem->prefix != NULL)
1346 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001347#ifdef LIBXML_REGEXP_ENABLED
1348 if (elem->contModel != NULL)
1349 xmlRegFreeRegexp(elem->contModel);
1350#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001351 xmlFree(elem);
1352}
1353
1354
1355/**
1356 * xmlAddElementDecl:
1357 * @ctxt: the validation context
1358 * @dtd: pointer to the DTD
1359 * @name: the entity name
1360 * @type: the element type
1361 * @content: the element content tree or NULL
1362 *
1363 * Register a new element declaration
1364 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001365 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001366 */
1367xmlElementPtr
William M. Brackedb65a72004-02-06 07:36:04 +00001368xmlAddElementDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001369 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001370 xmlElementTypeVal type,
1371 xmlElementContentPtr content) {
1372 xmlElementPtr ret;
1373 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001374 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001375 xmlChar *ns, *uqname;
1376
1377 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001378 return(NULL);
1379 }
1380 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001381 return(NULL);
1382 }
Daniel Veillard316a5c32005-01-23 22:56:39 +00001383
Owen Taylor3473f882001-02-23 17:55:21 +00001384 switch (type) {
1385 case XML_ELEMENT_TYPE_EMPTY:
1386 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001387 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1388 "xmlAddElementDecl: content != NULL for EMPTY\n",
1389 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001390 return(NULL);
1391 }
1392 break;
1393 case XML_ELEMENT_TYPE_ANY:
1394 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001395 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1396 "xmlAddElementDecl: content != NULL for ANY\n",
1397 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001398 return(NULL);
1399 }
1400 break;
1401 case XML_ELEMENT_TYPE_MIXED:
1402 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001403 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1404 "xmlAddElementDecl: content == NULL for MIXED\n",
1405 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001406 return(NULL);
1407 }
1408 break;
1409 case XML_ELEMENT_TYPE_ELEMENT:
1410 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001411 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1412 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1413 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001414 return(NULL);
1415 }
1416 break;
1417 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001418 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1419 "Internal: ELEMENT decl corrupted invalid type\n",
1420 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001421 return(NULL);
1422 }
1423
1424 /*
1425 * check if name is a QName
1426 */
1427 uqname = xmlSplitQName2(name, &ns);
1428 if (uqname != NULL)
1429 name = uqname;
1430
1431 /*
1432 * Create the Element table if needed.
1433 */
1434 table = (xmlElementTablePtr) dtd->elements;
1435 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00001436 xmlDictPtr dict = NULL;
1437
1438 if (dtd->doc != NULL)
1439 dict = dtd->doc->dict;
1440 table = xmlHashCreateDict(0, dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001441 dtd->elements = (void *) table;
1442 }
1443 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001444 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001445 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001446 if (uqname != NULL)
1447 xmlFree(uqname);
1448 if (ns != NULL)
1449 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001450 return(NULL);
1451 }
1452
Daniel Veillarda10efa82001-04-18 13:09:01 +00001453 /*
1454 * lookup old attributes inserted on an undefined element in the
1455 * internal subset.
1456 */
1457 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1458 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1459 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1460 oldAttributes = ret->attributes;
1461 ret->attributes = NULL;
1462 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1463 xmlFreeElement(ret);
1464 }
Owen Taylor3473f882001-02-23 17:55:21 +00001465 }
Owen Taylor3473f882001-02-23 17:55:21 +00001466
1467 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001468 * The element may already be present if one of its attribute
1469 * was registered first
1470 */
1471 ret = xmlHashLookup2(table, name, ns);
1472 if (ret != NULL) {
1473 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001474#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001475 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001476 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001477 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001478 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1479 "Redefinition of element %s\n",
1480 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001481#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001482 if (uqname != NULL)
1483 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001484 if (ns != NULL)
1485 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001486 return(NULL);
1487 }
William M. Brackd6e347e2005-04-15 01:34:41 +00001488 if (ns != NULL) {
1489 xmlFree(ns);
1490 ns = NULL;
1491 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001492 } else {
1493 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1494 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001495 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001496 if (uqname != NULL)
1497 xmlFree(uqname);
1498 if (ns != NULL)
1499 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001500 return(NULL);
1501 }
1502 memset(ret, 0, sizeof(xmlElement));
1503 ret->type = XML_ELEMENT_DECL;
1504
1505 /*
1506 * fill the structure.
1507 */
1508 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001509 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001510 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001511 if (uqname != NULL)
1512 xmlFree(uqname);
1513 if (ns != NULL)
1514 xmlFree(ns);
1515 xmlFree(ret);
1516 return(NULL);
1517 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001518 ret->prefix = ns;
1519
1520 /*
1521 * Validity Check:
1522 * Insertion must not fail
1523 */
1524 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001525#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001526 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001527 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001528 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001529 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1530 "Redefinition of element %s\n",
1531 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001532#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001533 xmlFreeElement(ret);
1534 if (uqname != NULL)
1535 xmlFree(uqname);
1536 return(NULL);
1537 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001538 /*
1539 * For new element, may have attributes from earlier
1540 * definition in internal subset
1541 */
1542 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001543 }
1544
1545 /*
1546 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001547 */
1548 ret->etype = type;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001549 /*
1550 * Avoid a stupid copy when called by the parser
1551 * and flag it by setting a special parent value
1552 * so the parser doesn't unallocate it.
1553 */
Daniel Veillardc394f732005-01-26 00:04:52 +00001554 if ((ctxt != NULL) &&
1555 ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
1556 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001557 ret->content = content;
1558 if (content != NULL)
1559 content->parent = (xmlElementContentPtr) 1;
1560 } else {
1561 ret->content = xmlCopyDocElementContent(dtd->doc, content);
1562 }
Owen Taylor3473f882001-02-23 17:55:21 +00001563
1564 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001565 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001566 */
1567 ret->parent = dtd;
1568 ret->doc = dtd->doc;
1569 if (dtd->last == NULL) {
1570 dtd->children = dtd->last = (xmlNodePtr) ret;
1571 } else {
1572 dtd->last->next = (xmlNodePtr) ret;
1573 ret->prev = dtd->last;
1574 dtd->last = (xmlNodePtr) ret;
1575 }
1576 if (uqname != NULL)
1577 xmlFree(uqname);
1578 return(ret);
1579}
1580
1581/**
1582 * xmlFreeElementTable:
1583 * @table: An element table
1584 *
1585 * Deallocate the memory used by an element hash table.
1586 */
1587void
1588xmlFreeElementTable(xmlElementTablePtr table) {
1589 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1590}
1591
Daniel Veillard652327a2003-09-29 18:02:38 +00001592#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001593/**
1594 * xmlCopyElement:
1595 * @elem: An element
1596 *
1597 * Build a copy of an element.
1598 *
1599 * Returns the new xmlElementPtr or NULL in case of error.
1600 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001601static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001602xmlCopyElement(xmlElementPtr elem) {
1603 xmlElementPtr cur;
1604
1605 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1606 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001607 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001608 return(NULL);
1609 }
1610 memset(cur, 0, sizeof(xmlElement));
1611 cur->type = XML_ELEMENT_DECL;
1612 cur->etype = elem->etype;
1613 if (elem->name != NULL)
1614 cur->name = xmlStrdup(elem->name);
1615 else
1616 cur->name = NULL;
1617 if (elem->prefix != NULL)
1618 cur->prefix = xmlStrdup(elem->prefix);
1619 else
1620 cur->prefix = NULL;
1621 cur->content = xmlCopyElementContent(elem->content);
1622 /* TODO : rebuild the attribute list on the copy */
1623 cur->attributes = NULL;
1624 return(cur);
1625}
1626
1627/**
1628 * xmlCopyElementTable:
1629 * @table: An element table
1630 *
1631 * Build a copy of an element table.
1632 *
1633 * Returns the new xmlElementTablePtr or NULL in case of error.
1634 */
1635xmlElementTablePtr
1636xmlCopyElementTable(xmlElementTablePtr table) {
1637 return((xmlElementTablePtr) xmlHashCopy(table,
1638 (xmlHashCopier) xmlCopyElement));
1639}
Daniel Veillard652327a2003-09-29 18:02:38 +00001640#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001641
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001642#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001643/**
1644 * xmlDumpElementDecl:
1645 * @buf: the XML buffer output
1646 * @elem: An element table
1647 *
1648 * This will dump the content of the element declaration as an XML
1649 * DTD definition
1650 */
1651void
1652xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001653 if ((buf == NULL) || (elem == NULL))
1654 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001655 switch (elem->etype) {
1656 case XML_ELEMENT_TYPE_EMPTY:
1657 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001658 if (elem->prefix != NULL) {
1659 xmlBufferWriteCHAR(buf, elem->prefix);
1660 xmlBufferWriteChar(buf, ":");
1661 }
Owen Taylor3473f882001-02-23 17:55:21 +00001662 xmlBufferWriteCHAR(buf, elem->name);
1663 xmlBufferWriteChar(buf, " EMPTY>\n");
1664 break;
1665 case XML_ELEMENT_TYPE_ANY:
1666 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001667 if (elem->prefix != NULL) {
1668 xmlBufferWriteCHAR(buf, elem->prefix);
1669 xmlBufferWriteChar(buf, ":");
1670 }
Owen Taylor3473f882001-02-23 17:55:21 +00001671 xmlBufferWriteCHAR(buf, elem->name);
1672 xmlBufferWriteChar(buf, " ANY>\n");
1673 break;
1674 case XML_ELEMENT_TYPE_MIXED:
1675 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001676 if (elem->prefix != NULL) {
1677 xmlBufferWriteCHAR(buf, elem->prefix);
1678 xmlBufferWriteChar(buf, ":");
1679 }
Owen Taylor3473f882001-02-23 17:55:21 +00001680 xmlBufferWriteCHAR(buf, elem->name);
1681 xmlBufferWriteChar(buf, " ");
1682 xmlDumpElementContent(buf, elem->content, 1);
1683 xmlBufferWriteChar(buf, ">\n");
1684 break;
1685 case XML_ELEMENT_TYPE_ELEMENT:
1686 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001687 if (elem->prefix != NULL) {
1688 xmlBufferWriteCHAR(buf, elem->prefix);
1689 xmlBufferWriteChar(buf, ":");
1690 }
Owen Taylor3473f882001-02-23 17:55:21 +00001691 xmlBufferWriteCHAR(buf, elem->name);
1692 xmlBufferWriteChar(buf, " ");
1693 xmlDumpElementContent(buf, elem->content, 1);
1694 xmlBufferWriteChar(buf, ">\n");
1695 break;
1696 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001697 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1698 "Internal: ELEMENT struct corrupted invalid type\n",
1699 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001700 }
1701}
1702
1703/**
William M. Brack9e660592003-10-20 14:56:06 +00001704 * xmlDumpElementDeclScan:
1705 * @elem: An element table
1706 * @buf: the XML buffer output
1707 *
1708 * This routine is used by the hash scan function. It just reverses
1709 * the arguments.
1710 */
1711static void
1712xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1713 xmlDumpElementDecl(buf, elem);
1714}
1715
1716/**
Owen Taylor3473f882001-02-23 17:55:21 +00001717 * xmlDumpElementTable:
1718 * @buf: the XML buffer output
1719 * @table: An element table
1720 *
1721 * This will dump the content of the element table as an XML DTD definition
1722 */
1723void
1724xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001725 if ((buf == NULL) || (table == NULL))
1726 return;
William M. Brack9e660592003-10-20 14:56:06 +00001727 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001728}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001729#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001730
1731/**
1732 * xmlCreateEnumeration:
1733 * @name: the enumeration name or NULL
1734 *
1735 * create and initialize an enumeration attribute node.
1736 *
1737 * Returns the xmlEnumerationPtr just created or NULL in case
1738 * of error.
1739 */
1740xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001741xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001742 xmlEnumerationPtr ret;
1743
1744 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1745 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001746 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001747 return(NULL);
1748 }
1749 memset(ret, 0, sizeof(xmlEnumeration));
1750
1751 if (name != NULL)
1752 ret->name = xmlStrdup(name);
1753 return(ret);
1754}
1755
1756/**
1757 * xmlFreeEnumeration:
1758 * @cur: the tree to free.
1759 *
1760 * free an enumeration attribute node (recursive).
1761 */
1762void
1763xmlFreeEnumeration(xmlEnumerationPtr cur) {
1764 if (cur == NULL) return;
1765
1766 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1767
1768 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001769 xmlFree(cur);
1770}
1771
Daniel Veillard652327a2003-09-29 18:02:38 +00001772#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001773/**
1774 * xmlCopyEnumeration:
1775 * @cur: the tree to copy.
1776 *
1777 * Copy an enumeration attribute node (recursive).
1778 *
1779 * Returns the xmlEnumerationPtr just created or NULL in case
1780 * of error.
1781 */
1782xmlEnumerationPtr
1783xmlCopyEnumeration(xmlEnumerationPtr cur) {
1784 xmlEnumerationPtr ret;
1785
1786 if (cur == NULL) return(NULL);
1787 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1788
1789 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1790 else ret->next = NULL;
1791
1792 return(ret);
1793}
Daniel Veillard652327a2003-09-29 18:02:38 +00001794#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001795
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001796#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001797/**
1798 * xmlDumpEnumeration:
1799 * @buf: the XML buffer output
1800 * @enum: An enumeration
1801 *
1802 * This will dump the content of the enumeration
1803 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001804static void
Owen Taylor3473f882001-02-23 17:55:21 +00001805xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001806 if ((buf == NULL) || (cur == NULL))
1807 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001808
1809 xmlBufferWriteCHAR(buf, cur->name);
1810 if (cur->next == NULL)
1811 xmlBufferWriteChar(buf, ")");
1812 else {
1813 xmlBufferWriteChar(buf, " | ");
1814 xmlDumpEnumeration(buf, cur->next);
1815 }
1816}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001817#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001818
Daniel Veillard4432df22003-09-28 18:58:27 +00001819#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001820/**
1821 * xmlScanAttributeDeclCallback:
1822 * @attr: the attribute decl
1823 * @list: the list to update
1824 *
1825 * Callback called by xmlScanAttributeDecl when a new attribute
1826 * has to be entered in the list.
1827 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001828static void
Owen Taylor3473f882001-02-23 17:55:21 +00001829xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001830 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001831 attr->nexth = *list;
1832 *list = attr;
1833}
1834
1835/**
1836 * xmlScanAttributeDecl:
1837 * @dtd: pointer to the DTD
1838 * @elem: the element name
1839 *
1840 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001841 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001842 *
1843 * Returns the pointer to the first attribute decl in the chain,
1844 * possibly NULL.
1845 */
1846xmlAttributePtr
1847xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1848 xmlAttributePtr ret = NULL;
1849 xmlAttributeTablePtr table;
1850
1851 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001852 return(NULL);
1853 }
1854 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001855 return(NULL);
1856 }
1857 table = (xmlAttributeTablePtr) dtd->attributes;
1858 if (table == NULL)
1859 return(NULL);
1860
1861 /* WRONG !!! */
1862 xmlHashScan3(table, NULL, NULL, elem,
1863 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1864 return(ret);
1865}
1866
1867/**
1868 * xmlScanIDAttributeDecl:
1869 * @ctxt: the validation context
1870 * @elem: the element name
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001871 * @err: whether to raise errors here
Owen Taylor3473f882001-02-23 17:55:21 +00001872 *
1873 * Verify that the element don't have too many ID attributes
1874 * declared.
1875 *
1876 * Returns the number of ID attributes found.
1877 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001878static int
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001879xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
Owen Taylor3473f882001-02-23 17:55:21 +00001880 xmlAttributePtr cur;
1881 int ret = 0;
1882
1883 if (elem == NULL) return(0);
1884 cur = elem->attributes;
1885 while (cur != NULL) {
1886 if (cur->atype == XML_ATTRIBUTE_ID) {
1887 ret ++;
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001888 if ((ret > 1) && (err))
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001889 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001890 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001891 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001892 }
1893 cur = cur->nexth;
1894 }
1895 return(ret);
1896}
Daniel Veillard4432df22003-09-28 18:58:27 +00001897#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001898
1899/**
1900 * xmlFreeAttribute:
1901 * @elem: An attribute
1902 *
1903 * Deallocate the memory used by an attribute definition
1904 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001905static void
Owen Taylor3473f882001-02-23 17:55:21 +00001906xmlFreeAttribute(xmlAttributePtr attr) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001907 xmlDictPtr dict;
1908
Owen Taylor3473f882001-02-23 17:55:21 +00001909 if (attr == NULL) return;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001910 if (attr->doc != NULL)
1911 dict = attr->doc->dict;
1912 else
1913 dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001914 xmlUnlinkNode((xmlNodePtr) attr);
1915 if (attr->tree != NULL)
1916 xmlFreeEnumeration(attr->tree);
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001917 if (dict) {
1918 if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1919 xmlFree((xmlChar *) attr->elem);
1920 if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1921 xmlFree((xmlChar *) attr->name);
1922 if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1923 xmlFree((xmlChar *) attr->prefix);
1924 if ((attr->defaultValue != NULL) &&
1925 (!xmlDictOwns(dict, attr->defaultValue)))
1926 xmlFree((xmlChar *) attr->defaultValue);
1927 } else {
1928 if (attr->elem != NULL)
1929 xmlFree((xmlChar *) attr->elem);
1930 if (attr->name != NULL)
1931 xmlFree((xmlChar *) attr->name);
1932 if (attr->defaultValue != NULL)
1933 xmlFree((xmlChar *) attr->defaultValue);
1934 if (attr->prefix != NULL)
1935 xmlFree((xmlChar *) attr->prefix);
1936 }
Owen Taylor3473f882001-02-23 17:55:21 +00001937 xmlFree(attr);
1938}
1939
1940
1941/**
1942 * xmlAddAttributeDecl:
1943 * @ctxt: the validation context
1944 * @dtd: pointer to the DTD
1945 * @elem: the element name
1946 * @name: the attribute name
1947 * @ns: the attribute namespace prefix
1948 * @type: the attribute type
1949 * @def: the attribute default type
1950 * @defaultValue: the attribute default value
1951 * @tree: if it's an enumeration, the associated list
1952 *
1953 * Register a new attribute declaration
1954 * Note that @tree becomes the ownership of the DTD
1955 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001956 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001957 */
1958xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001959xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001960 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001961 const xmlChar *name, const xmlChar *ns,
1962 xmlAttributeType type, xmlAttributeDefault def,
1963 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1964 xmlAttributePtr ret;
1965 xmlAttributeTablePtr table;
1966 xmlElementPtr elemDef;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001967 xmlDictPtr dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001968
1969 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001970 xmlFreeEnumeration(tree);
1971 return(NULL);
1972 }
1973 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001974 xmlFreeEnumeration(tree);
1975 return(NULL);
1976 }
1977 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001978 xmlFreeEnumeration(tree);
1979 return(NULL);
1980 }
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001981 if (dtd->doc != NULL)
1982 dict = dtd->doc->dict;
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001983
Daniel Veillard4432df22003-09-28 18:58:27 +00001984#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001985 /*
1986 * Check the type and possibly the default value.
1987 */
1988 switch (type) {
1989 case XML_ATTRIBUTE_CDATA:
1990 break;
1991 case XML_ATTRIBUTE_ID:
1992 break;
1993 case XML_ATTRIBUTE_IDREF:
1994 break;
1995 case XML_ATTRIBUTE_IDREFS:
1996 break;
1997 case XML_ATTRIBUTE_ENTITY:
1998 break;
1999 case XML_ATTRIBUTE_ENTITIES:
2000 break;
2001 case XML_ATTRIBUTE_NMTOKEN:
2002 break;
2003 case XML_ATTRIBUTE_NMTOKENS:
2004 break;
2005 case XML_ATTRIBUTE_ENUMERATION:
2006 break;
2007 case XML_ATTRIBUTE_NOTATION:
2008 break;
2009 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002010 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
2011 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2012 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002013 xmlFreeEnumeration(tree);
2014 return(NULL);
2015 }
2016 if ((defaultValue != NULL) &&
2017 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002018 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
2019 "Attribute %s of %s: invalid default value\n",
2020 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00002021 defaultValue = NULL;
Daniel Veillard42595322004-11-08 10:52:06 +00002022 if (ctxt != NULL)
2023 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002024 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002025#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002026
2027 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00002028 * Check first that an attribute defined in the external subset wasn't
2029 * already defined in the internal subset
2030 */
2031 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2032 (dtd->doc->intSubset != NULL) &&
2033 (dtd->doc->intSubset->attributes != NULL)) {
2034 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2035 if (ret != NULL)
2036 return(NULL);
2037 }
2038
2039 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002040 * Create the Attribute table if needed.
2041 */
2042 table = (xmlAttributeTablePtr) dtd->attributes;
2043 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00002044 table = xmlHashCreateDict(0, dict);
Owen Taylor3473f882001-02-23 17:55:21 +00002045 dtd->attributes = (void *) table;
2046 }
2047 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002048 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002049 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002050 return(NULL);
2051 }
2052
2053
2054 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2055 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002056 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002057 return(NULL);
2058 }
2059 memset(ret, 0, sizeof(xmlAttribute));
2060 ret->type = XML_ATTRIBUTE_DECL;
2061
2062 /*
2063 * fill the structure.
2064 */
2065 ret->atype = type;
William M. Brackf810de02005-07-06 22:48:41 +00002066 /*
2067 * doc must be set before possible error causes call
2068 * to xmlFreeAttribute (because it's used to check on
2069 * dict use)
2070 */
2071 ret->doc = dtd->doc;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002072 if (dict) {
2073 ret->name = xmlDictLookup(dict, name, -1);
2074 ret->prefix = xmlDictLookup(dict, ns, -1);
2075 ret->elem = xmlDictLookup(dict, elem, -1);
2076 } else {
2077 ret->name = xmlStrdup(name);
2078 ret->prefix = xmlStrdup(ns);
2079 ret->elem = xmlStrdup(elem);
2080 }
Owen Taylor3473f882001-02-23 17:55:21 +00002081 ret->def = def;
2082 ret->tree = tree;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002083 if (defaultValue != NULL) {
2084 if (dict)
2085 ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2086 else
2087 ret->defaultValue = xmlStrdup(defaultValue);
2088 }
Owen Taylor3473f882001-02-23 17:55:21 +00002089
2090 /*
2091 * Validity Check:
2092 * Search the DTD for previous declarations of the ATTLIST
2093 */
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002094 if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002095#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002096 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002097 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002098 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002099 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00002100 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002101 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00002102#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002103 xmlFreeAttribute(ret);
2104 return(NULL);
2105 }
2106
2107 /*
2108 * Validity Check:
2109 * Multiple ID per element
2110 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00002111 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002112 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00002113
Daniel Veillard4432df22003-09-28 18:58:27 +00002114#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002115 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillarddbee0f12005-06-27 13:42:57 +00002116 (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002117 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00002118 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002119 elem, name, NULL);
Daniel Veillard42595322004-11-08 10:52:06 +00002120 if (ctxt != NULL)
2121 ctxt->valid = 0;
Daniel Veillardc7612992002-02-17 22:47:37 +00002122 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002123#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00002124
Daniel Veillard48da9102001-08-07 01:10:10 +00002125 /*
2126 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002127 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00002128 */
2129 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2130 ((ret->prefix != NULL &&
2131 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2132 ret->nexth = elemDef->attributes;
2133 elemDef->attributes = ret;
2134 } else {
2135 xmlAttributePtr tmp = elemDef->attributes;
2136
2137 while ((tmp != NULL) &&
2138 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2139 ((ret->prefix != NULL &&
2140 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2141 if (tmp->nexth == NULL)
2142 break;
2143 tmp = tmp->nexth;
2144 }
2145 if (tmp != NULL) {
2146 ret->nexth = tmp->nexth;
2147 tmp->nexth = ret;
2148 } else {
2149 ret->nexth = elemDef->attributes;
2150 elemDef->attributes = ret;
2151 }
2152 }
Owen Taylor3473f882001-02-23 17:55:21 +00002153 }
2154
2155 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002156 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00002157 */
2158 ret->parent = dtd;
Owen Taylor3473f882001-02-23 17:55:21 +00002159 if (dtd->last == NULL) {
2160 dtd->children = dtd->last = (xmlNodePtr) ret;
2161 } else {
2162 dtd->last->next = (xmlNodePtr) ret;
2163 ret->prev = dtd->last;
2164 dtd->last = (xmlNodePtr) ret;
2165 }
2166 return(ret);
2167}
2168
2169/**
2170 * xmlFreeAttributeTable:
2171 * @table: An attribute table
2172 *
2173 * Deallocate the memory used by an entities hash table.
2174 */
2175void
2176xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2177 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
2178}
2179
Daniel Veillard652327a2003-09-29 18:02:38 +00002180#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002181/**
2182 * xmlCopyAttribute:
2183 * @attr: An attribute
2184 *
2185 * Build a copy of an attribute.
2186 *
2187 * Returns the new xmlAttributePtr or NULL in case of error.
2188 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002189static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002190xmlCopyAttribute(xmlAttributePtr attr) {
2191 xmlAttributePtr cur;
2192
2193 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2194 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002195 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002196 return(NULL);
2197 }
2198 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00002199 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00002200 cur->atype = attr->atype;
2201 cur->def = attr->def;
2202 cur->tree = xmlCopyEnumeration(attr->tree);
2203 if (attr->elem != NULL)
2204 cur->elem = xmlStrdup(attr->elem);
2205 if (attr->name != NULL)
2206 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002207 if (attr->prefix != NULL)
2208 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002209 if (attr->defaultValue != NULL)
2210 cur->defaultValue = xmlStrdup(attr->defaultValue);
2211 return(cur);
2212}
2213
2214/**
2215 * xmlCopyAttributeTable:
2216 * @table: An attribute table
2217 *
2218 * Build a copy of an attribute table.
2219 *
2220 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2221 */
2222xmlAttributeTablePtr
2223xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2224 return((xmlAttributeTablePtr) xmlHashCopy(table,
2225 (xmlHashCopier) xmlCopyAttribute));
2226}
Daniel Veillard652327a2003-09-29 18:02:38 +00002227#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002228
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002229#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002230/**
2231 * xmlDumpAttributeDecl:
2232 * @buf: the XML buffer output
2233 * @attr: An attribute declaration
2234 *
2235 * This will dump the content of the attribute declaration as an XML
2236 * DTD definition
2237 */
2238void
2239xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002240 if ((buf == NULL) || (attr == NULL))
2241 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002242 xmlBufferWriteChar(buf, "<!ATTLIST ");
2243 xmlBufferWriteCHAR(buf, attr->elem);
2244 xmlBufferWriteChar(buf, " ");
2245 if (attr->prefix != NULL) {
2246 xmlBufferWriteCHAR(buf, attr->prefix);
2247 xmlBufferWriteChar(buf, ":");
2248 }
2249 xmlBufferWriteCHAR(buf, attr->name);
2250 switch (attr->atype) {
2251 case XML_ATTRIBUTE_CDATA:
2252 xmlBufferWriteChar(buf, " CDATA");
2253 break;
2254 case XML_ATTRIBUTE_ID:
2255 xmlBufferWriteChar(buf, " ID");
2256 break;
2257 case XML_ATTRIBUTE_IDREF:
2258 xmlBufferWriteChar(buf, " IDREF");
2259 break;
2260 case XML_ATTRIBUTE_IDREFS:
2261 xmlBufferWriteChar(buf, " IDREFS");
2262 break;
2263 case XML_ATTRIBUTE_ENTITY:
2264 xmlBufferWriteChar(buf, " ENTITY");
2265 break;
2266 case XML_ATTRIBUTE_ENTITIES:
2267 xmlBufferWriteChar(buf, " ENTITIES");
2268 break;
2269 case XML_ATTRIBUTE_NMTOKEN:
2270 xmlBufferWriteChar(buf, " NMTOKEN");
2271 break;
2272 case XML_ATTRIBUTE_NMTOKENS:
2273 xmlBufferWriteChar(buf, " NMTOKENS");
2274 break;
2275 case XML_ATTRIBUTE_ENUMERATION:
2276 xmlBufferWriteChar(buf, " (");
2277 xmlDumpEnumeration(buf, attr->tree);
2278 break;
2279 case XML_ATTRIBUTE_NOTATION:
2280 xmlBufferWriteChar(buf, " NOTATION (");
2281 xmlDumpEnumeration(buf, attr->tree);
2282 break;
2283 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002284 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2285 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2286 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002287 }
2288 switch (attr->def) {
2289 case XML_ATTRIBUTE_NONE:
2290 break;
2291 case XML_ATTRIBUTE_REQUIRED:
2292 xmlBufferWriteChar(buf, " #REQUIRED");
2293 break;
2294 case XML_ATTRIBUTE_IMPLIED:
2295 xmlBufferWriteChar(buf, " #IMPLIED");
2296 break;
2297 case XML_ATTRIBUTE_FIXED:
2298 xmlBufferWriteChar(buf, " #FIXED");
2299 break;
2300 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002301 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2302 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2303 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002304 }
2305 if (attr->defaultValue != NULL) {
2306 xmlBufferWriteChar(buf, " ");
2307 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2308 }
2309 xmlBufferWriteChar(buf, ">\n");
2310}
2311
2312/**
William M. Brack9e660592003-10-20 14:56:06 +00002313 * xmlDumpAttributeDeclScan:
2314 * @attr: An attribute declaration
2315 * @buf: the XML buffer output
2316 *
2317 * This is used with the hash scan function - just reverses arguments
2318 */
2319static void
2320xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2321 xmlDumpAttributeDecl(buf, attr);
2322}
2323
2324/**
Owen Taylor3473f882001-02-23 17:55:21 +00002325 * xmlDumpAttributeTable:
2326 * @buf: the XML buffer output
2327 * @table: An attribute table
2328 *
2329 * This will dump the content of the attribute table as an XML DTD definition
2330 */
2331void
2332xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002333 if ((buf == NULL) || (table == NULL))
2334 return;
William M. Brack9e660592003-10-20 14:56:06 +00002335 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002336}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002337#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002338
2339/************************************************************************
2340 * *
2341 * NOTATIONs *
2342 * *
2343 ************************************************************************/
2344/**
Owen Taylor3473f882001-02-23 17:55:21 +00002345 * xmlFreeNotation:
2346 * @not: A notation
2347 *
2348 * Deallocate the memory used by an notation definition
2349 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002350static void
Owen Taylor3473f882001-02-23 17:55:21 +00002351xmlFreeNotation(xmlNotationPtr nota) {
2352 if (nota == NULL) return;
2353 if (nota->name != NULL)
2354 xmlFree((xmlChar *) nota->name);
2355 if (nota->PublicID != NULL)
2356 xmlFree((xmlChar *) nota->PublicID);
2357 if (nota->SystemID != NULL)
2358 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002359 xmlFree(nota);
2360}
2361
2362
2363/**
2364 * xmlAddNotationDecl:
2365 * @dtd: pointer to the DTD
2366 * @ctxt: the validation context
2367 * @name: the entity name
2368 * @PublicID: the public identifier or NULL
2369 * @SystemID: the system identifier or NULL
2370 *
2371 * Register a new notation declaration
2372 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002373 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002374 */
2375xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002376xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002377 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002378 const xmlChar *PublicID, const xmlChar *SystemID) {
2379 xmlNotationPtr ret;
2380 xmlNotationTablePtr table;
2381
2382 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002383 return(NULL);
2384 }
2385 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002386 return(NULL);
2387 }
2388 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002389 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002390 }
2391
2392 /*
2393 * Create the Notation table if needed.
2394 */
2395 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002396 if (table == NULL) {
2397 xmlDictPtr dict = NULL;
2398 if (dtd->doc != NULL)
2399 dict = dtd->doc->dict;
2400
2401 dtd->notations = table = xmlHashCreateDict(0, dict);
2402 }
Owen Taylor3473f882001-02-23 17:55:21 +00002403 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002404 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002405 "xmlAddNotationDecl: Table creation failed!\n");
2406 return(NULL);
2407 }
2408
2409 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2410 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002411 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002412 return(NULL);
2413 }
2414 memset(ret, 0, sizeof(xmlNotation));
2415
2416 /*
2417 * fill the structure.
2418 */
2419 ret->name = xmlStrdup(name);
2420 if (SystemID != NULL)
2421 ret->SystemID = xmlStrdup(SystemID);
2422 if (PublicID != NULL)
2423 ret->PublicID = xmlStrdup(PublicID);
2424
2425 /*
2426 * Validity Check:
2427 * Check the DTD for previous declarations of the ATTLIST
2428 */
2429 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002430#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002431 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2432 "xmlAddNotationDecl: %s already defined\n",
2433 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002434#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002435 xmlFreeNotation(ret);
2436 return(NULL);
2437 }
2438 return(ret);
2439}
2440
2441/**
2442 * xmlFreeNotationTable:
2443 * @table: An notation table
2444 *
2445 * Deallocate the memory used by an entities hash table.
2446 */
2447void
2448xmlFreeNotationTable(xmlNotationTablePtr table) {
2449 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2450}
2451
Daniel Veillard652327a2003-09-29 18:02:38 +00002452#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002453/**
2454 * xmlCopyNotation:
2455 * @nota: A notation
2456 *
2457 * Build a copy of a notation.
2458 *
2459 * Returns the new xmlNotationPtr or NULL in case of error.
2460 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002461static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002462xmlCopyNotation(xmlNotationPtr nota) {
2463 xmlNotationPtr cur;
2464
2465 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2466 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002467 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002468 return(NULL);
2469 }
2470 if (nota->name != NULL)
2471 cur->name = xmlStrdup(nota->name);
2472 else
2473 cur->name = NULL;
2474 if (nota->PublicID != NULL)
2475 cur->PublicID = xmlStrdup(nota->PublicID);
2476 else
2477 cur->PublicID = NULL;
2478 if (nota->SystemID != NULL)
2479 cur->SystemID = xmlStrdup(nota->SystemID);
2480 else
2481 cur->SystemID = NULL;
2482 return(cur);
2483}
2484
2485/**
2486 * xmlCopyNotationTable:
2487 * @table: A notation table
2488 *
2489 * Build a copy of a notation table.
2490 *
2491 * Returns the new xmlNotationTablePtr or NULL in case of error.
2492 */
2493xmlNotationTablePtr
2494xmlCopyNotationTable(xmlNotationTablePtr table) {
2495 return((xmlNotationTablePtr) xmlHashCopy(table,
2496 (xmlHashCopier) xmlCopyNotation));
2497}
Daniel Veillard652327a2003-09-29 18:02:38 +00002498#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002499
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002500#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002501/**
2502 * xmlDumpNotationDecl:
2503 * @buf: the XML buffer output
2504 * @nota: A notation declaration
2505 *
2506 * This will dump the content the notation declaration as an XML DTD definition
2507 */
2508void
2509xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002510 if ((buf == NULL) || (nota == NULL))
2511 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002512 xmlBufferWriteChar(buf, "<!NOTATION ");
2513 xmlBufferWriteCHAR(buf, nota->name);
2514 if (nota->PublicID != NULL) {
2515 xmlBufferWriteChar(buf, " PUBLIC ");
2516 xmlBufferWriteQuotedString(buf, nota->PublicID);
2517 if (nota->SystemID != NULL) {
2518 xmlBufferWriteChar(buf, " ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002519 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002520 }
2521 } else {
2522 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002523 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002524 }
2525 xmlBufferWriteChar(buf, " >\n");
2526}
2527
2528/**
William M. Brack9e660592003-10-20 14:56:06 +00002529 * xmlDumpNotationDeclScan:
2530 * @nota: A notation declaration
2531 * @buf: the XML buffer output
2532 *
2533 * This is called with the hash scan function, and just reverses args
2534 */
2535static void
2536xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2537 xmlDumpNotationDecl(buf, nota);
2538}
2539
2540/**
Owen Taylor3473f882001-02-23 17:55:21 +00002541 * xmlDumpNotationTable:
2542 * @buf: the XML buffer output
2543 * @table: A notation table
2544 *
2545 * This will dump the content of the notation table as an XML DTD definition
2546 */
2547void
2548xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002549 if ((buf == NULL) || (table == NULL))
2550 return;
William M. Brack9e660592003-10-20 14:56:06 +00002551 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002552}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002553#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002554
2555/************************************************************************
2556 * *
2557 * IDs *
2558 * *
2559 ************************************************************************/
2560/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002561 * DICT_FREE:
2562 * @str: a string
2563 *
2564 * Free a string if it is not owned by the "dict" dictionnary in the
2565 * current scope
2566 */
2567#define DICT_FREE(str) \
2568 if ((str) && ((!dict) || \
2569 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2570 xmlFree((char *)(str));
2571
2572/**
Owen Taylor3473f882001-02-23 17:55:21 +00002573 * xmlFreeID:
2574 * @not: A id
2575 *
2576 * Deallocate the memory used by an id definition
2577 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002578static void
Owen Taylor3473f882001-02-23 17:55:21 +00002579xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002580 xmlDictPtr dict = NULL;
2581
Owen Taylor3473f882001-02-23 17:55:21 +00002582 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002583
2584 if (id->doc != NULL)
2585 dict = id->doc->dict;
2586
Owen Taylor3473f882001-02-23 17:55:21 +00002587 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002588 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002589 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002590 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002591 xmlFree(id);
2592}
2593
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002594
Owen Taylor3473f882001-02-23 17:55:21 +00002595/**
2596 * xmlAddID:
2597 * @ctxt: the validation context
2598 * @doc: pointer to the document
2599 * @value: the value name
2600 * @attr: the attribute holding the ID
2601 *
2602 * Register a new id declaration
2603 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002604 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002605 */
2606xmlIDPtr
2607xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2608 xmlAttrPtr attr) {
2609 xmlIDPtr ret;
2610 xmlIDTablePtr table;
2611
2612 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002613 return(NULL);
2614 }
2615 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002616 return(NULL);
2617 }
2618 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002619 return(NULL);
2620 }
2621
2622 /*
2623 * Create the ID table if needed.
2624 */
2625 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002626 if (table == NULL) {
2627 doc->ids = table = xmlHashCreateDict(0, doc->dict);
2628 }
Owen Taylor3473f882001-02-23 17:55:21 +00002629 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002630 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002631 "xmlAddID: Table creation failed!\n");
2632 return(NULL);
2633 }
2634
2635 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2636 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002637 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002638 return(NULL);
2639 }
2640
2641 /*
2642 * fill the structure.
2643 */
2644 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002645 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002646 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2647 /*
2648 * Operating in streaming mode, attr is gonna disapear
2649 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002650 if (doc->dict != NULL)
2651 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2652 else
2653 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002654 ret->attr = NULL;
2655 } else {
2656 ret->attr = attr;
2657 ret->name = NULL;
2658 }
2659 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002660
2661 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002662#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002663 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002664 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002665 */
Daniel Veillardd3669b22004-02-25 12:34:55 +00002666 if ((ctxt != NULL) && (ctxt->error != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002667 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2668 "ID %s already defined\n",
2669 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002670 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002671#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002672 xmlFreeID(ret);
2673 return(NULL);
2674 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002675 if (attr != NULL)
2676 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002677 return(ret);
2678}
2679
2680/**
2681 * xmlFreeIDTable:
2682 * @table: An id table
2683 *
2684 * Deallocate the memory used by an ID hash table.
2685 */
2686void
2687xmlFreeIDTable(xmlIDTablePtr table) {
2688 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2689}
2690
2691/**
2692 * xmlIsID:
2693 * @doc: the document
2694 * @elem: the element carrying the attribute
2695 * @attr: the attribute
2696 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002697 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002698 * then this is done if DTD loading has been requested. In the case
2699 * of HTML documents parsed with the HTML parser, then ID detection is
2700 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002701 *
2702 * Returns 0 or 1 depending on the lookup result
2703 */
2704int
2705xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00002706 if ((attr == NULL) || (attr->name == NULL)) return(0);
2707 if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2708 (!strcmp((char *) attr->name, "id")) &&
2709 (!strcmp((char *) attr->ns->prefix, "xml")))
2710 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002711 if (doc == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002712 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2713 return(0);
2714 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Rob Richards04bffc02006-03-03 16:44:37 +00002715 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2716 ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
2717 ((elem == NULL) || (!xmlStrEqual(elem->name, BAD_CAST "input")))))
Owen Taylor3473f882001-02-23 17:55:21 +00002718 return(1);
2719 return(0);
Daniel Veillard379a3b72005-08-12 10:18:14 +00002720 } else if (elem == NULL) {
2721 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002722 } else {
Daniel Veillard465a0002005-08-22 12:07:04 +00002723 xmlAttributePtr attrDecl = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002724
Daniel Veillard379a3b72005-08-12 10:18:14 +00002725 xmlChar felem[50], fattr[50];
2726 xmlChar *fullelemname, *fullattrname;
2727
2728 fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2729 xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2730 (xmlChar *)elem->name;
2731
2732 fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2733 xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2734 (xmlChar *)attr->name;
2735
2736 if (fullelemname != NULL && fullattrname != NULL) {
2737 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2738 fullattrname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002739 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillard379a3b72005-08-12 10:18:14 +00002740 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2741 fullattrname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002742 }
Owen Taylor3473f882001-02-23 17:55:21 +00002743
Daniel Veillard379a3b72005-08-12 10:18:14 +00002744 if ((fullattrname != fattr) && (fullattrname != attr->name))
2745 xmlFree(fullattrname);
2746 if ((fullelemname != felem) && (fullelemname != elem->name))
2747 xmlFree(fullelemname);
2748
Owen Taylor3473f882001-02-23 17:55:21 +00002749 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2750 return(1);
2751 }
2752 return(0);
2753}
2754
2755/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002756 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002757 * @doc: the document
2758 * @attr: the attribute
2759 *
2760 * Remove the given attribute from the ID table maintained internally.
2761 *
2762 * Returns -1 if the lookup failed and 0 otherwise
2763 */
2764int
2765xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002766 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002767 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002768 xmlChar *ID;
2769
2770 if (doc == NULL) return(-1);
2771 if (attr == NULL) return(-1);
2772 table = (xmlIDTablePtr) doc->ids;
2773 if (table == NULL)
2774 return(-1);
2775
2776 if (attr == NULL)
2777 return(-1);
2778 ID = xmlNodeListGetString(doc, attr->children, 1);
2779 if (ID == NULL)
2780 return(-1);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002781 id = xmlHashLookup(table, ID);
2782 if (id == NULL || id->attr != attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002783 xmlFree(ID);
2784 return(-1);
2785 }
Daniel Veillard91b955c2004-12-10 10:26:42 +00002786 xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID);
Owen Taylor3473f882001-02-23 17:55:21 +00002787 xmlFree(ID);
Daniel Veillardda6f4af2005-06-20 17:17:54 +00002788 attr->atype = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002789 return(0);
2790}
2791
2792/**
2793 * xmlGetID:
2794 * @doc: pointer to the document
2795 * @ID: the ID value
2796 *
2797 * Search the attribute declaring the given ID
2798 *
2799 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2800 */
2801xmlAttrPtr
2802xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2803 xmlIDTablePtr table;
2804 xmlIDPtr id;
2805
2806 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002807 return(NULL);
2808 }
2809
2810 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002811 return(NULL);
2812 }
2813
2814 table = (xmlIDTablePtr) doc->ids;
2815 if (table == NULL)
2816 return(NULL);
2817
2818 id = xmlHashLookup(table, ID);
2819 if (id == NULL)
2820 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002821 if (id->attr == NULL) {
2822 /*
2823 * We are operating on a stream, return a well known reference
2824 * since the attribute node doesn't exist anymore
2825 */
2826 return((xmlAttrPtr) doc);
2827 }
Owen Taylor3473f882001-02-23 17:55:21 +00002828 return(id->attr);
2829}
2830
2831/************************************************************************
2832 * *
2833 * Refs *
2834 * *
2835 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002836typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002837{
2838 xmlListPtr l;
2839 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002840} xmlRemoveMemo;
2841
2842typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2843
2844typedef struct xmlValidateMemo_t
2845{
2846 xmlValidCtxtPtr ctxt;
2847 const xmlChar *name;
2848} xmlValidateMemo;
2849
2850typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002851
2852/**
Owen Taylor3473f882001-02-23 17:55:21 +00002853 * xmlFreeRef:
2854 * @lk: A list link
2855 *
2856 * Deallocate the memory used by a ref definition
2857 */
2858static void
2859xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002860 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2861 if (ref == NULL) return;
2862 if (ref->value != NULL)
2863 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002864 if (ref->name != NULL)
2865 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002866 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002867}
2868
2869/**
2870 * xmlFreeRefList:
2871 * @list_ref: A list of references.
2872 *
2873 * Deallocate the memory used by a list of references
2874 */
2875static void
2876xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002877 if (list_ref == NULL) return;
2878 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002879}
2880
2881/**
2882 * xmlWalkRemoveRef:
2883 * @data: Contents of current link
2884 * @user: Value supplied by the user
2885 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002886 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002887 */
2888static int
2889xmlWalkRemoveRef(const void *data, const void *user)
2890{
Daniel Veillard37721922001-05-04 15:21:12 +00002891 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2892 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2893 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002894
Daniel Veillard37721922001-05-04 15:21:12 +00002895 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2896 xmlListRemoveFirst(ref_list, (void *)data);
2897 return 0;
2898 }
2899 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002900}
2901
2902/**
Daniel Veillard770075b2004-02-25 10:44:30 +00002903 * xmlDummyCompare
2904 * @data0: Value supplied by the user
2905 * @data1: Value supplied by the user
2906 *
2907 * Do nothing, return 0. Used to create unordered lists.
2908 */
2909static int
Daniel Veillardf54cd532004-02-25 11:52:31 +00002910xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2911 const void *data1 ATTRIBUTE_UNUSED)
Daniel Veillard770075b2004-02-25 10:44:30 +00002912{
2913 return (0);
2914}
2915
2916/**
Owen Taylor3473f882001-02-23 17:55:21 +00002917 * xmlAddRef:
2918 * @ctxt: the validation context
2919 * @doc: pointer to the document
2920 * @value: the value name
2921 * @attr: the attribute holding the Ref
2922 *
2923 * Register a new ref declaration
2924 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002925 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002926 */
2927xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002928xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002929 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002930 xmlRefPtr ret;
2931 xmlRefTablePtr table;
2932 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002933
Daniel Veillard37721922001-05-04 15:21:12 +00002934 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002935 return(NULL);
2936 }
2937 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002938 return(NULL);
2939 }
2940 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002941 return(NULL);
2942 }
Owen Taylor3473f882001-02-23 17:55:21 +00002943
Daniel Veillard37721922001-05-04 15:21:12 +00002944 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002945 * Create the Ref table if needed.
2946 */
Daniel Veillard37721922001-05-04 15:21:12 +00002947 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002948 if (table == NULL) {
2949 doc->refs = table = xmlHashCreateDict(0, doc->dict);
2950 }
Daniel Veillard37721922001-05-04 15:21:12 +00002951 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002952 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002953 "xmlAddRef: Table creation failed!\n");
2954 return(NULL);
2955 }
Owen Taylor3473f882001-02-23 17:55:21 +00002956
Daniel Veillard37721922001-05-04 15:21:12 +00002957 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2958 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002959 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002960 return(NULL);
2961 }
Owen Taylor3473f882001-02-23 17:55:21 +00002962
Daniel Veillard37721922001-05-04 15:21:12 +00002963 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002964 * fill the structure.
2965 */
Daniel Veillard37721922001-05-04 15:21:12 +00002966 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002967 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2968 /*
2969 * Operating in streaming mode, attr is gonna disapear
2970 */
2971 ret->name = xmlStrdup(attr->name);
2972 ret->attr = NULL;
2973 } else {
2974 ret->name = NULL;
2975 ret->attr = attr;
2976 }
2977 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002978
Daniel Veillard37721922001-05-04 15:21:12 +00002979 /* To add a reference :-
2980 * References are maintained as a list of references,
2981 * Lookup the entry, if no entry create new nodelist
2982 * Add the owning node to the NodeList
2983 * Return the ref
2984 */
Owen Taylor3473f882001-02-23 17:55:21 +00002985
Daniel Veillard37721922001-05-04 15:21:12 +00002986 if (NULL == (ref_list = xmlHashLookup(table, value))) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002987 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002988 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2989 "xmlAddRef: Reference list creation failed!\n",
2990 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002991 return(NULL);
2992 }
2993 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2994 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002995 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2996 "xmlAddRef: Reference list insertion failed!\n",
2997 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002998 return(NULL);
2999 }
3000 }
Daniel Veillard965983a2004-02-17 16:30:24 +00003001/* xmlListInsert(ref_list, ret); */
3002 xmlListAppend(ref_list, ret);
Daniel Veillard37721922001-05-04 15:21:12 +00003003 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003004}
3005
3006/**
3007 * xmlFreeRefTable:
3008 * @table: An ref table
3009 *
3010 * Deallocate the memory used by an Ref hash table.
3011 */
3012void
3013xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00003014 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00003015}
3016
3017/**
3018 * xmlIsRef:
3019 * @doc: the document
3020 * @elem: the element carrying the attribute
3021 * @attr: the attribute
3022 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003023 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00003024 * then this is simple, otherwise we use an heuristic: name Ref (upper
3025 * or lowercase).
3026 *
3027 * Returns 0 or 1 depending on the lookup result
3028 */
3029int
3030xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003031 if (attr == NULL)
3032 return(0);
3033 if (doc == NULL) {
3034 doc = attr->doc;
3035 if (doc == NULL) return(0);
3036 }
3037
Daniel Veillard37721922001-05-04 15:21:12 +00003038 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3039 return(0);
3040 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3041 /* TODO @@@ */
3042 return(0);
3043 } else {
3044 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00003045
Daniel Veillardce244ad2004-11-05 10:03:46 +00003046 if (elem == NULL) return(0);
Daniel Veillard37721922001-05-04 15:21:12 +00003047 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3048 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3049 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3050 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00003051
Daniel Veillard37721922001-05-04 15:21:12 +00003052 if ((attrDecl != NULL) &&
3053 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3054 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3055 return(1);
3056 }
3057 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003058}
3059
3060/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003061 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00003062 * @doc: the document
3063 * @attr: the attribute
3064 *
3065 * Remove the given attribute from the Ref table maintained internally.
3066 *
3067 * Returns -1 if the lookup failed and 0 otherwise
3068 */
3069int
3070xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00003071 xmlListPtr ref_list;
3072 xmlRefTablePtr table;
3073 xmlChar *ID;
3074 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00003075
Daniel Veillard37721922001-05-04 15:21:12 +00003076 if (doc == NULL) return(-1);
3077 if (attr == NULL) return(-1);
3078 table = (xmlRefTablePtr) doc->refs;
3079 if (table == NULL)
3080 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003081
Daniel Veillard37721922001-05-04 15:21:12 +00003082 if (attr == NULL)
3083 return(-1);
3084 ID = xmlNodeListGetString(doc, attr->children, 1);
3085 if (ID == NULL)
3086 return(-1);
3087 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00003088
Daniel Veillard37721922001-05-04 15:21:12 +00003089 if(ref_list == NULL) {
3090 xmlFree(ID);
3091 return (-1);
3092 }
3093 /* At this point, ref_list refers to a list of references which
3094 * have the same key as the supplied attr. Our list of references
3095 * is ordered by reference address and we don't have that information
3096 * here to use when removing. We'll have to walk the list and
3097 * check for a matching attribute, when we find one stop the walk
3098 * and remove the entry.
3099 * The list is ordered by reference, so that means we don't have the
3100 * key. Passing the list and the reference to the walker means we
3101 * will have enough data to be able to remove the entry.
3102 */
3103 target.l = ref_list;
3104 target.ap = attr;
3105
3106 /* Remove the supplied attr from our list */
3107 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00003108
Daniel Veillard37721922001-05-04 15:21:12 +00003109 /*If the list is empty then remove the list entry in the hash */
3110 if (xmlListEmpty(ref_list))
3111 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
3112 xmlFreeRefList);
3113 xmlFree(ID);
3114 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003115}
3116
3117/**
3118 * xmlGetRefs:
3119 * @doc: pointer to the document
3120 * @ID: the ID value
3121 *
3122 * Find the set of references for the supplied ID.
3123 *
3124 * Returns NULL if not found, otherwise node set for the ID.
3125 */
3126xmlListPtr
3127xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00003128 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00003129
Daniel Veillard37721922001-05-04 15:21:12 +00003130 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003131 return(NULL);
3132 }
Owen Taylor3473f882001-02-23 17:55:21 +00003133
Daniel Veillard37721922001-05-04 15:21:12 +00003134 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003135 return(NULL);
3136 }
Owen Taylor3473f882001-02-23 17:55:21 +00003137
Daniel Veillard37721922001-05-04 15:21:12 +00003138 table = (xmlRefTablePtr) doc->refs;
3139 if (table == NULL)
3140 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003141
Daniel Veillard37721922001-05-04 15:21:12 +00003142 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00003143}
3144
3145/************************************************************************
3146 * *
3147 * Routines for validity checking *
3148 * *
3149 ************************************************************************/
3150
3151/**
3152 * xmlGetDtdElementDesc:
3153 * @dtd: a pointer to the DtD to search
3154 * @name: the element name
3155 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003156 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003157 *
3158 * returns the xmlElementPtr if found or NULL
3159 */
3160
3161xmlElementPtr
3162xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3163 xmlElementTablePtr table;
3164 xmlElementPtr cur;
3165 xmlChar *uqname = NULL, *prefix = NULL;
3166
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00003167 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003168 if (dtd->elements == NULL)
3169 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003170 table = (xmlElementTablePtr) dtd->elements;
3171
3172 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003173 if (uqname != NULL)
3174 name = uqname;
3175 cur = xmlHashLookup2(table, name, prefix);
3176 if (prefix != NULL) xmlFree(prefix);
3177 if (uqname != NULL) xmlFree(uqname);
3178 return(cur);
3179}
3180/**
3181 * xmlGetDtdElementDesc2:
3182 * @dtd: a pointer to the DtD to search
3183 * @name: the element name
3184 * @create: create an empty description if not found
3185 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003186 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00003187 *
3188 * returns the xmlElementPtr if found or NULL
3189 */
3190
Daniel Veillard86fd5a72001-12-13 14:55:21 +00003191static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00003192xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3193 xmlElementTablePtr table;
3194 xmlElementPtr cur;
3195 xmlChar *uqname = NULL, *prefix = NULL;
3196
3197 if (dtd == NULL) return(NULL);
3198 if (dtd->elements == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003199 xmlDictPtr dict = NULL;
3200
3201 if (dtd->doc != NULL)
3202 dict = dtd->doc->dict;
3203
Daniel Veillarda10efa82001-04-18 13:09:01 +00003204 if (!create)
3205 return(NULL);
3206 /*
3207 * Create the Element table if needed.
3208 */
3209 table = (xmlElementTablePtr) dtd->elements;
3210 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003211 table = xmlHashCreateDict(0, dict);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003212 dtd->elements = (void *) table;
3213 }
3214 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003215 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003216 return(NULL);
3217 }
3218 }
3219 table = (xmlElementTablePtr) dtd->elements;
3220
3221 uqname = xmlSplitQName2(name, &prefix);
3222 if (uqname != NULL)
3223 name = uqname;
3224 cur = xmlHashLookup2(table, name, prefix);
3225 if ((cur == NULL) && (create)) {
3226 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3227 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003228 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003229 return(NULL);
3230 }
3231 memset(cur, 0, sizeof(xmlElement));
3232 cur->type = XML_ELEMENT_DECL;
3233
3234 /*
3235 * fill the structure.
3236 */
3237 cur->name = xmlStrdup(name);
3238 cur->prefix = xmlStrdup(prefix);
3239 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3240
3241 xmlHashAddEntry2(table, name, prefix, cur);
3242 }
3243 if (prefix != NULL) xmlFree(prefix);
3244 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003245 return(cur);
3246}
3247
3248/**
3249 * xmlGetDtdQElementDesc:
3250 * @dtd: a pointer to the DtD to search
3251 * @name: the element name
3252 * @prefix: the element namespace prefix
3253 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003254 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003255 *
3256 * returns the xmlElementPtr if found or NULL
3257 */
3258
Daniel Veillard48da9102001-08-07 01:10:10 +00003259xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003260xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3261 const xmlChar *prefix) {
3262 xmlElementTablePtr table;
3263
3264 if (dtd == NULL) return(NULL);
3265 if (dtd->elements == NULL) return(NULL);
3266 table = (xmlElementTablePtr) dtd->elements;
3267
3268 return(xmlHashLookup2(table, name, prefix));
3269}
3270
3271/**
3272 * xmlGetDtdAttrDesc:
3273 * @dtd: a pointer to the DtD to search
3274 * @elem: the element name
3275 * @name: the attribute name
3276 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003277 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003278 * this element.
3279 *
3280 * returns the xmlAttributePtr if found or NULL
3281 */
3282
3283xmlAttributePtr
3284xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3285 xmlAttributeTablePtr table;
3286 xmlAttributePtr cur;
3287 xmlChar *uqname = NULL, *prefix = NULL;
3288
3289 if (dtd == NULL) return(NULL);
3290 if (dtd->attributes == NULL) return(NULL);
3291
3292 table = (xmlAttributeTablePtr) dtd->attributes;
3293 if (table == NULL)
3294 return(NULL);
3295
3296 uqname = xmlSplitQName2(name, &prefix);
3297
3298 if (uqname != NULL) {
3299 cur = xmlHashLookup3(table, uqname, prefix, elem);
3300 if (prefix != NULL) xmlFree(prefix);
3301 if (uqname != NULL) xmlFree(uqname);
3302 } else
3303 cur = xmlHashLookup3(table, name, NULL, elem);
3304 return(cur);
3305}
3306
3307/**
3308 * xmlGetDtdQAttrDesc:
3309 * @dtd: a pointer to the DtD to search
3310 * @elem: the element name
3311 * @name: the attribute name
3312 * @prefix: the attribute namespace prefix
3313 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003314 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003315 * this element.
3316 *
3317 * returns the xmlAttributePtr if found or NULL
3318 */
3319
Daniel Veillard48da9102001-08-07 01:10:10 +00003320xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003321xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3322 const xmlChar *prefix) {
3323 xmlAttributeTablePtr table;
3324
3325 if (dtd == NULL) return(NULL);
3326 if (dtd->attributes == NULL) return(NULL);
3327 table = (xmlAttributeTablePtr) dtd->attributes;
3328
3329 return(xmlHashLookup3(table, name, prefix, elem));
3330}
3331
3332/**
3333 * xmlGetDtdNotationDesc:
3334 * @dtd: a pointer to the DtD to search
3335 * @name: the notation name
3336 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003337 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003338 *
3339 * returns the xmlNotationPtr if found or NULL
3340 */
3341
3342xmlNotationPtr
3343xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3344 xmlNotationTablePtr table;
3345
3346 if (dtd == NULL) return(NULL);
3347 if (dtd->notations == NULL) return(NULL);
3348 table = (xmlNotationTablePtr) dtd->notations;
3349
3350 return(xmlHashLookup(table, name));
3351}
3352
Daniel Veillardf54cd532004-02-25 11:52:31 +00003353#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003354/**
3355 * xmlValidateNotationUse:
3356 * @ctxt: the validation context
3357 * @doc: the document
3358 * @notationName: the notation name to check
3359 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003360 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003361 * - [ VC: Notation Declared ]
3362 *
3363 * returns 1 if valid or 0 otherwise
3364 */
3365
3366int
3367xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3368 const xmlChar *notationName) {
3369 xmlNotationPtr notaDecl;
3370 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3371
3372 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3373 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3374 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3375
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003376 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003377 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3378 "NOTATION %s is not declared\n",
3379 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003380 return(0);
3381 }
3382 return(1);
3383}
Daniel Veillardf54cd532004-02-25 11:52:31 +00003384#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003385
3386/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003387 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003388 * @doc: the document
3389 * @name: the element name
3390 *
3391 * Search in the DtDs whether an element accept Mixed content (or ANY)
3392 * basically if it is supposed to accept text childs
3393 *
3394 * returns 0 if no, 1 if yes, and -1 if no element description is available
3395 */
3396
3397int
3398xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3399 xmlElementPtr elemDecl;
3400
3401 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3402
3403 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3404 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3405 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3406 if (elemDecl == NULL) return(-1);
3407 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003408 case XML_ELEMENT_TYPE_UNDEFINED:
3409 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003410 case XML_ELEMENT_TYPE_ELEMENT:
3411 return(0);
3412 case XML_ELEMENT_TYPE_EMPTY:
3413 /*
3414 * return 1 for EMPTY since we want VC error to pop up
3415 * on <empty> </empty> for example
3416 */
3417 case XML_ELEMENT_TYPE_ANY:
3418 case XML_ELEMENT_TYPE_MIXED:
3419 return(1);
3420 }
3421 return(1);
3422}
3423
Daniel Veillard4432df22003-09-28 18:58:27 +00003424#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003425/**
3426 * xmlValidateNameValue:
3427 * @value: an Name value
3428 *
3429 * Validate that the given value match Name production
3430 *
3431 * returns 1 if valid or 0 otherwise
3432 */
3433
Daniel Veillard9b731d72002-04-14 12:56:08 +00003434int
Owen Taylor3473f882001-02-23 17:55:21 +00003435xmlValidateNameValue(const xmlChar *value) {
3436 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003437 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003438
3439 if (value == NULL) return(0);
3440 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003441 val = xmlStringCurrentChar(NULL, cur, &len);
3442 cur += len;
3443 if (!IS_LETTER(val) && (val != '_') &&
3444 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003445 return(0);
3446 }
3447
Daniel Veillardd8224e02002-01-13 15:43:22 +00003448 val = xmlStringCurrentChar(NULL, cur, &len);
3449 cur += len;
3450 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3451 (val == '.') || (val == '-') ||
3452 (val == '_') || (val == ':') ||
3453 (IS_COMBINING(val)) ||
3454 (IS_EXTENDER(val))) {
3455 val = xmlStringCurrentChar(NULL, cur, &len);
3456 cur += len;
3457 }
Owen Taylor3473f882001-02-23 17:55:21 +00003458
Daniel Veillardd8224e02002-01-13 15:43:22 +00003459 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003460
3461 return(1);
3462}
3463
3464/**
3465 * xmlValidateNamesValue:
3466 * @value: an Names value
3467 *
3468 * Validate that the given value match Names production
3469 *
3470 * returns 1 if valid or 0 otherwise
3471 */
3472
Daniel Veillard9b731d72002-04-14 12:56:08 +00003473int
Owen Taylor3473f882001-02-23 17:55:21 +00003474xmlValidateNamesValue(const xmlChar *value) {
3475 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003476 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003477
3478 if (value == NULL) return(0);
3479 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003480 val = xmlStringCurrentChar(NULL, cur, &len);
3481 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003482
Daniel Veillardd8224e02002-01-13 15:43:22 +00003483 if (!IS_LETTER(val) && (val != '_') &&
3484 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003485 return(0);
3486 }
3487
Daniel Veillardd8224e02002-01-13 15:43:22 +00003488 val = xmlStringCurrentChar(NULL, cur, &len);
3489 cur += len;
3490 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3491 (val == '.') || (val == '-') ||
3492 (val == '_') || (val == ':') ||
3493 (IS_COMBINING(val)) ||
3494 (IS_EXTENDER(val))) {
3495 val = xmlStringCurrentChar(NULL, cur, &len);
3496 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003497 }
3498
Daniel Veillard807b4de2004-09-26 14:42:56 +00003499 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3500 while (val == 0x20) {
3501 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003502 val = xmlStringCurrentChar(NULL, cur, &len);
3503 cur += len;
3504 }
3505
3506 if (!IS_LETTER(val) && (val != '_') &&
3507 (val != ':')) {
3508 return(0);
3509 }
3510 val = xmlStringCurrentChar(NULL, cur, &len);
3511 cur += len;
3512
3513 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3514 (val == '.') || (val == '-') ||
3515 (val == '_') || (val == ':') ||
3516 (IS_COMBINING(val)) ||
3517 (IS_EXTENDER(val))) {
3518 val = xmlStringCurrentChar(NULL, cur, &len);
3519 cur += len;
3520 }
3521 }
3522
3523 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003524
3525 return(1);
3526}
3527
3528/**
3529 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003530 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003531 *
3532 * Validate that the given value match Nmtoken production
3533 *
3534 * [ VC: Name Token ]
3535 *
3536 * returns 1 if valid or 0 otherwise
3537 */
3538
Daniel Veillard9b731d72002-04-14 12:56:08 +00003539int
Owen Taylor3473f882001-02-23 17:55:21 +00003540xmlValidateNmtokenValue(const xmlChar *value) {
3541 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003542 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003543
3544 if (value == NULL) return(0);
3545 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003546 val = xmlStringCurrentChar(NULL, cur, &len);
3547 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003548
Daniel Veillardd8224e02002-01-13 15:43:22 +00003549 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3550 (val != '.') && (val != '-') &&
3551 (val != '_') && (val != ':') &&
3552 (!IS_COMBINING(val)) &&
3553 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003554 return(0);
3555
Daniel Veillardd8224e02002-01-13 15:43:22 +00003556 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3557 (val == '.') || (val == '-') ||
3558 (val == '_') || (val == ':') ||
3559 (IS_COMBINING(val)) ||
3560 (IS_EXTENDER(val))) {
3561 val = xmlStringCurrentChar(NULL, cur, &len);
3562 cur += len;
3563 }
Owen Taylor3473f882001-02-23 17:55:21 +00003564
Daniel Veillardd8224e02002-01-13 15:43:22 +00003565 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003566
3567 return(1);
3568}
3569
3570/**
3571 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003572 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003573 *
3574 * Validate that the given value match Nmtokens production
3575 *
3576 * [ VC: Name Token ]
3577 *
3578 * returns 1 if valid or 0 otherwise
3579 */
3580
Daniel Veillard9b731d72002-04-14 12:56:08 +00003581int
Owen Taylor3473f882001-02-23 17:55:21 +00003582xmlValidateNmtokensValue(const xmlChar *value) {
3583 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003584 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003585
3586 if (value == NULL) return(0);
3587 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003588 val = xmlStringCurrentChar(NULL, cur, &len);
3589 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003590
Daniel Veillardd8224e02002-01-13 15:43:22 +00003591 while (IS_BLANK(val)) {
3592 val = xmlStringCurrentChar(NULL, cur, &len);
3593 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003594 }
3595
Daniel Veillardd8224e02002-01-13 15:43:22 +00003596 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3597 (val != '.') && (val != '-') &&
3598 (val != '_') && (val != ':') &&
3599 (!IS_COMBINING(val)) &&
3600 (!IS_EXTENDER(val)))
3601 return(0);
3602
3603 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3604 (val == '.') || (val == '-') ||
3605 (val == '_') || (val == ':') ||
3606 (IS_COMBINING(val)) ||
3607 (IS_EXTENDER(val))) {
3608 val = xmlStringCurrentChar(NULL, cur, &len);
3609 cur += len;
3610 }
3611
Daniel Veillard807b4de2004-09-26 14:42:56 +00003612 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3613 while (val == 0x20) {
3614 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003615 val = xmlStringCurrentChar(NULL, cur, &len);
3616 cur += len;
3617 }
3618 if (val == 0) return(1);
3619
3620 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3621 (val != '.') && (val != '-') &&
3622 (val != '_') && (val != ':') &&
3623 (!IS_COMBINING(val)) &&
3624 (!IS_EXTENDER(val)))
3625 return(0);
3626
3627 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3628 (val == '.') || (val == '-') ||
3629 (val == '_') || (val == ':') ||
3630 (IS_COMBINING(val)) ||
3631 (IS_EXTENDER(val))) {
3632 val = xmlStringCurrentChar(NULL, cur, &len);
3633 cur += len;
3634 }
3635 }
3636
3637 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003638
3639 return(1);
3640}
3641
3642/**
3643 * xmlValidateNotationDecl:
3644 * @ctxt: the validation context
3645 * @doc: a document instance
3646 * @nota: a notation definition
3647 *
3648 * Try to validate a single notation definition
3649 * basically it does the following checks as described by the
3650 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003651 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003652 * But this function get called anyway ...
3653 *
3654 * returns 1 if valid or 0 otherwise
3655 */
3656
3657int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003658xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3659 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003660 int ret = 1;
3661
3662 return(ret);
3663}
3664
3665/**
3666 * xmlValidateAttributeValue:
3667 * @type: an attribute type
3668 * @value: an attribute value
3669 *
3670 * Validate that the given attribute value match the proper production
3671 *
3672 * [ VC: ID ]
3673 * Values of type ID must match the Name production....
3674 *
3675 * [ VC: IDREF ]
3676 * Values of type IDREF must match the Name production, and values
3677 * of type IDREFS must match Names ...
3678 *
3679 * [ VC: Entity Name ]
3680 * Values of type ENTITY must match the Name production, values
3681 * of type ENTITIES must match Names ...
3682 *
3683 * [ VC: Name Token ]
3684 * Values of type NMTOKEN must match the Nmtoken production; values
3685 * of type NMTOKENS must match Nmtokens.
3686 *
3687 * returns 1 if valid or 0 otherwise
3688 */
3689
3690int
3691xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3692 switch (type) {
3693 case XML_ATTRIBUTE_ENTITIES:
3694 case XML_ATTRIBUTE_IDREFS:
3695 return(xmlValidateNamesValue(value));
3696 case XML_ATTRIBUTE_ENTITY:
3697 case XML_ATTRIBUTE_IDREF:
3698 case XML_ATTRIBUTE_ID:
3699 case XML_ATTRIBUTE_NOTATION:
3700 return(xmlValidateNameValue(value));
3701 case XML_ATTRIBUTE_NMTOKENS:
3702 case XML_ATTRIBUTE_ENUMERATION:
3703 return(xmlValidateNmtokensValue(value));
3704 case XML_ATTRIBUTE_NMTOKEN:
3705 return(xmlValidateNmtokenValue(value));
3706 case XML_ATTRIBUTE_CDATA:
3707 break;
3708 }
3709 return(1);
3710}
3711
3712/**
3713 * xmlValidateAttributeValue2:
3714 * @ctxt: the validation context
3715 * @doc: the document
3716 * @name: the attribute name (used for error reporting only)
3717 * @type: the attribute type
3718 * @value: the attribute value
3719 *
3720 * Validate that the given attribute value match a given type.
3721 * This typically cannot be done before having finished parsing
3722 * the subsets.
3723 *
3724 * [ VC: IDREF ]
3725 * Values of type IDREF must match one of the declared IDs
3726 * Values of type IDREFS must match a sequence of the declared IDs
3727 * each Name must match the value of an ID attribute on some element
3728 * in the XML document; i.e. IDREF values must match the value of
3729 * some ID attribute
3730 *
3731 * [ VC: Entity Name ]
3732 * Values of type ENTITY must match one declared entity
3733 * Values of type ENTITIES must match a sequence of declared entities
3734 *
3735 * [ VC: Notation Attributes ]
3736 * all notation names in the declaration must be declared.
3737 *
3738 * returns 1 if valid or 0 otherwise
3739 */
3740
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003741static int
Owen Taylor3473f882001-02-23 17:55:21 +00003742xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3743 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3744 int ret = 1;
3745 switch (type) {
3746 case XML_ATTRIBUTE_IDREFS:
3747 case XML_ATTRIBUTE_IDREF:
3748 case XML_ATTRIBUTE_ID:
3749 case XML_ATTRIBUTE_NMTOKENS:
3750 case XML_ATTRIBUTE_ENUMERATION:
3751 case XML_ATTRIBUTE_NMTOKEN:
3752 case XML_ATTRIBUTE_CDATA:
3753 break;
3754 case XML_ATTRIBUTE_ENTITY: {
3755 xmlEntityPtr ent;
3756
3757 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003758 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003759 if ((ent == NULL) && (doc->standalone == 1)) {
3760 doc->standalone = 0;
3761 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003762 }
Owen Taylor3473f882001-02-23 17:55:21 +00003763 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003764 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3765 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003766 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003767 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003768 ret = 0;
3769 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003770 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3771 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003772 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003773 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003774 ret = 0;
3775 }
3776 break;
3777 }
3778 case XML_ATTRIBUTE_ENTITIES: {
3779 xmlChar *dup, *nam = NULL, *cur, save;
3780 xmlEntityPtr ent;
3781
3782 dup = xmlStrdup(value);
3783 if (dup == NULL)
3784 return(0);
3785 cur = dup;
3786 while (*cur != 0) {
3787 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003788 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003789 save = *cur;
3790 *cur = 0;
3791 ent = xmlGetDocEntity(doc, nam);
3792 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003793 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3794 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003795 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003796 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003797 ret = 0;
3798 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003799 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3800 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003801 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003802 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003803 ret = 0;
3804 }
3805 if (save == 0)
3806 break;
3807 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003808 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003809 }
3810 xmlFree(dup);
3811 break;
3812 }
3813 case XML_ATTRIBUTE_NOTATION: {
3814 xmlNotationPtr nota;
3815
3816 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3817 if ((nota == NULL) && (doc->extSubset != NULL))
3818 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3819
3820 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003821 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3822 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003823 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003824 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003825 ret = 0;
3826 }
3827 break;
3828 }
3829 }
3830 return(ret);
3831}
3832
3833/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003834 * xmlValidCtxtNormalizeAttributeValue:
3835 * @ctxt: the validation context
3836 * @doc: the document
3837 * @elem: the parent
3838 * @name: the attribute name
3839 * @value: the attribute value
3840 * @ctxt: the validation context or NULL
3841 *
3842 * Does the validation related extra step of the normalization of attribute
3843 * values:
3844 *
3845 * If the declared value is not CDATA, then the XML processor must further
3846 * process the normalized attribute value by discarding any leading and
3847 * trailing space (#x20) characters, and by replacing sequences of space
3848 * (#x20) characters by single space (#x20) character.
3849 *
3850 * Also check VC: Standalone Document Declaration in P32, and update
3851 * ctxt->valid accordingly
3852 *
3853 * returns a new normalized string if normalization is needed, NULL otherwise
3854 * the caller must free the returned value.
3855 */
3856
3857xmlChar *
3858xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3859 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3860 xmlChar *ret, *dst;
3861 const xmlChar *src;
3862 xmlAttributePtr attrDecl = NULL;
3863 int extsubset = 0;
3864
3865 if (doc == NULL) return(NULL);
3866 if (elem == NULL) return(NULL);
3867 if (name == NULL) return(NULL);
3868 if (value == NULL) return(NULL);
3869
3870 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003871 xmlChar fn[50];
3872 xmlChar *fullname;
3873
3874 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3875 if (fullname == NULL)
Daniel Veillard24505b02005-07-28 23:49:35 +00003876 return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00003877 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003878 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003879 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003880 if (attrDecl != NULL)
3881 extsubset = 1;
3882 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003883 if ((fullname != fn) && (fullname != elem->name))
3884 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003885 }
3886 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3887 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3888 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3889 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3890 if (attrDecl != NULL)
3891 extsubset = 1;
3892 }
3893
3894 if (attrDecl == NULL)
3895 return(NULL);
3896 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3897 return(NULL);
3898
3899 ret = xmlStrdup(value);
3900 if (ret == NULL)
3901 return(NULL);
3902 src = value;
3903 dst = ret;
3904 while (*src == 0x20) src++;
3905 while (*src != 0) {
3906 if (*src == 0x20) {
3907 while (*src == 0x20) src++;
3908 if (*src != 0)
3909 *dst++ = 0x20;
3910 } else {
3911 *dst++ = *src++;
3912 }
3913 }
3914 *dst = 0;
3915 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003916 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003917"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003918 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003919 ctxt->valid = 0;
3920 }
3921 return(ret);
3922}
3923
3924/**
Owen Taylor3473f882001-02-23 17:55:21 +00003925 * xmlValidNormalizeAttributeValue:
3926 * @doc: the document
3927 * @elem: the parent
3928 * @name: the attribute name
3929 * @value: the attribute value
3930 *
3931 * Does the validation related extra step of the normalization of attribute
3932 * values:
3933 *
3934 * If the declared value is not CDATA, then the XML processor must further
3935 * process the normalized attribute value by discarding any leading and
3936 * trailing space (#x20) characters, and by replacing sequences of space
3937 * (#x20) characters by single space (#x20) character.
3938 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003939 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003940 * the caller must free the returned value.
3941 */
3942
3943xmlChar *
3944xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3945 const xmlChar *name, const xmlChar *value) {
3946 xmlChar *ret, *dst;
3947 const xmlChar *src;
3948 xmlAttributePtr attrDecl = NULL;
3949
3950 if (doc == NULL) return(NULL);
3951 if (elem == NULL) return(NULL);
3952 if (name == NULL) return(NULL);
3953 if (value == NULL) return(NULL);
3954
3955 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003956 xmlChar fn[50];
3957 xmlChar *fullname;
3958
3959 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3960 if (fullname == NULL)
Daniel Veillard24505b02005-07-28 23:49:35 +00003961 return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00003962 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003963 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003964 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3965 if ((fullname != fn) && (fullname != elem->name))
3966 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003967 }
3968 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3969 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3970 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3971
3972 if (attrDecl == NULL)
3973 return(NULL);
3974 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3975 return(NULL);
3976
3977 ret = xmlStrdup(value);
3978 if (ret == NULL)
3979 return(NULL);
3980 src = value;
3981 dst = ret;
3982 while (*src == 0x20) src++;
3983 while (*src != 0) {
3984 if (*src == 0x20) {
3985 while (*src == 0x20) src++;
3986 if (*src != 0)
3987 *dst++ = 0x20;
3988 } else {
3989 *dst++ = *src++;
3990 }
3991 }
3992 *dst = 0;
3993 return(ret);
3994}
3995
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003996static void
Owen Taylor3473f882001-02-23 17:55:21 +00003997xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003998 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003999 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4000}
4001
4002/**
4003 * xmlValidateAttributeDecl:
4004 * @ctxt: the validation context
4005 * @doc: a document instance
4006 * @attr: an attribute definition
4007 *
4008 * Try to validate a single attribute definition
4009 * basically it does the following checks as described by the
4010 * XML-1.0 recommendation:
4011 * - [ VC: Attribute Default Legal ]
4012 * - [ VC: Enumeration ]
4013 * - [ VC: ID Attribute Default ]
4014 *
4015 * The ID/IDREF uniqueness and matching are done separately
4016 *
4017 * returns 1 if valid or 0 otherwise
4018 */
4019
4020int
4021xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4022 xmlAttributePtr attr) {
4023 int ret = 1;
4024 int val;
4025 CHECK_DTD;
4026 if(attr == NULL) return(1);
4027
4028 /* Attribute Default Legal */
4029 /* Enumeration */
4030 if (attr->defaultValue != NULL) {
4031 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
4032 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004033 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004034 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004035 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004036 }
4037 ret &= val;
4038 }
4039
4040 /* ID Attribute Default */
4041 if ((attr->atype == XML_ATTRIBUTE_ID)&&
4042 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4043 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004044 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004045 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004046 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004047 ret = 0;
4048 }
4049
4050 /* One ID per Element Type */
4051 if (attr->atype == XML_ATTRIBUTE_ID) {
4052 int nbId;
4053
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004054 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00004055 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4056 attr->elem);
4057 if (elem != NULL) {
Daniel Veillarddbee0f12005-06-27 13:42:57 +00004058 nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00004059 } else {
4060 xmlAttributeTablePtr table;
4061
4062 /*
4063 * The attribute may be declared in the internal subset and the
4064 * element in the external subset.
4065 */
4066 nbId = 0;
Daniel Veillard11ce4002006-03-10 00:36:23 +00004067 if (doc->intSubset != NULL) {
4068 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4069 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
4070 xmlValidateAttributeIdCallback, &nbId);
4071 }
Owen Taylor3473f882001-02-23 17:55:21 +00004072 }
4073 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004074
4075 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004076 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4077 attr->elem, nbId, attr->name);
4078 } else if (doc->extSubset != NULL) {
4079 int extId = 0;
4080 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4081 if (elem != NULL) {
Daniel Veillarddbee0f12005-06-27 13:42:57 +00004082 extId = xmlScanIDAttributeDecl(NULL, elem, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00004083 }
4084 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004085 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 external subset : %s\n",
4087 attr->elem, extId, attr->name);
4088 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004089 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004090"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004091 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004092 }
4093 }
4094 }
4095
4096 /* Validity Constraint: Enumeration */
4097 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4098 xmlEnumerationPtr tree = attr->tree;
4099 while (tree != NULL) {
4100 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4101 tree = tree->next;
4102 }
4103 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004104 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004105"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004106 attr->defaultValue, attr->name, attr->elem);
4107 ret = 0;
4108 }
4109 }
4110
4111 return(ret);
4112}
4113
4114/**
4115 * xmlValidateElementDecl:
4116 * @ctxt: the validation context
4117 * @doc: a document instance
4118 * @elem: an element definition
4119 *
4120 * Try to validate a single element definition
4121 * basically it does the following checks as described by the
4122 * XML-1.0 recommendation:
4123 * - [ VC: One ID per Element Type ]
4124 * - [ VC: No Duplicate Types ]
4125 * - [ VC: Unique Element Type Declaration ]
4126 *
4127 * returns 1 if valid or 0 otherwise
4128 */
4129
4130int
4131xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4132 xmlElementPtr elem) {
4133 int ret = 1;
4134 xmlElementPtr tst;
4135
4136 CHECK_DTD;
4137
4138 if (elem == NULL) return(1);
4139
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004140#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00004141#ifdef LIBXML_REGEXP_ENABLED
4142 /* Build the regexp associated to the content model */
4143 ret = xmlValidBuildContentModel(ctxt, elem);
4144#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004145#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00004146
Owen Taylor3473f882001-02-23 17:55:21 +00004147 /* No Duplicate Types */
4148 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4149 xmlElementContentPtr cur, next;
4150 const xmlChar *name;
4151
4152 cur = elem->content;
4153 while (cur != NULL) {
4154 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4155 if (cur->c1 == NULL) break;
4156 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4157 name = cur->c1->name;
4158 next = cur->c2;
4159 while (next != NULL) {
4160 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00004161 if ((xmlStrEqual(next->name, name)) &&
4162 (xmlStrEqual(next->prefix, cur->prefix))) {
4163 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004164 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00004165 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004166 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004167 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004168 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004169 "Definition of %s has duplicate references of %s:%s\n",
4170 elem->name, cur->prefix, name);
4171 }
Owen Taylor3473f882001-02-23 17:55:21 +00004172 ret = 0;
4173 }
4174 break;
4175 }
4176 if (next->c1 == NULL) break;
4177 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00004178 if ((xmlStrEqual(next->c1->name, name)) &&
4179 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
4180 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004181 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004182 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004183 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004184 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004185 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004186 "Definition of %s has duplicate references to %s:%s\n",
4187 elem->name, cur->prefix, name);
4188 }
Owen Taylor3473f882001-02-23 17:55:21 +00004189 ret = 0;
4190 }
4191 next = next->c2;
4192 }
4193 }
4194 cur = cur->c2;
4195 }
4196 }
4197
4198 /* VC: Unique Element Type Declaration */
4199 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004200 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004201 ((tst->prefix == elem->prefix) ||
4202 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004203 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004204 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4205 "Redefinition of element %s\n",
4206 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004207 ret = 0;
4208 }
4209 tst = xmlGetDtdElementDesc(doc->extSubset, 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 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004219 /* One ID per Element Type
4220 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004221 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4222 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004223 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004224 return(ret);
4225}
4226
4227/**
4228 * xmlValidateOneAttribute:
4229 * @ctxt: the validation context
4230 * @doc: a document instance
4231 * @elem: an element instance
4232 * @attr: an attribute instance
4233 * @value: the attribute value (without entities processing)
4234 *
4235 * Try to validate a single attribute for an element
4236 * basically it does the following checks as described by the
4237 * XML-1.0 recommendation:
4238 * - [ VC: Attribute Value Type ]
4239 * - [ VC: Fixed Attribute Default ]
4240 * - [ VC: Entity Name ]
4241 * - [ VC: Name Token ]
4242 * - [ VC: ID ]
4243 * - [ VC: IDREF ]
4244 * - [ VC: Entity Name ]
4245 * - [ VC: Notation Attributes ]
4246 *
4247 * The ID/IDREF uniqueness and matching are done separately
4248 *
4249 * returns 1 if valid or 0 otherwise
4250 */
4251
4252int
4253xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004254 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4255{
Owen Taylor3473f882001-02-23 17:55:21 +00004256 xmlAttributePtr attrDecl = NULL;
4257 int val;
4258 int ret = 1;
4259
4260 CHECK_DTD;
4261 if ((elem == NULL) || (elem->name == NULL)) return(0);
4262 if ((attr == NULL) || (attr->name == NULL)) return(0);
4263
4264 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004265 xmlChar fn[50];
4266 xmlChar *fullname;
4267
4268 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4269 if (fullname == NULL)
4270 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004271 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004272 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004273 attr->name, attr->ns->prefix);
4274 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004275 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004276 attr->name, attr->ns->prefix);
4277 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004278 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004279 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4280 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004281 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004282 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004283 if ((fullname != fn) && (fullname != elem->name))
4284 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004285 }
4286 if (attrDecl == NULL) {
4287 if (attr->ns != NULL) {
4288 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4289 attr->name, attr->ns->prefix);
4290 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4291 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4292 attr->name, attr->ns->prefix);
4293 } else {
4294 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4295 elem->name, attr->name);
4296 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4297 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4298 elem->name, attr->name);
4299 }
4300 }
4301
4302
4303 /* Validity Constraint: Attribute Value Type */
4304 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004305 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004306 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004307 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004308 return(0);
4309 }
4310 attr->atype = attrDecl->atype;
4311
4312 val = xmlValidateAttributeValue(attrDecl->atype, value);
4313 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004314 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004315 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004316 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004317 ret = 0;
4318 }
4319
4320 /* Validity constraint: Fixed Attribute Default */
4321 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4322 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004323 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004324 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004325 attr->name, elem->name, attrDecl->defaultValue);
4326 ret = 0;
4327 }
4328 }
4329
4330 /* Validity Constraint: ID uniqueness */
4331 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4332 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4333 ret = 0;
4334 }
4335
4336 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4337 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4338 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4339 ret = 0;
4340 }
4341
4342 /* Validity Constraint: Notation Attributes */
4343 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4344 xmlEnumerationPtr tree = attrDecl->tree;
4345 xmlNotationPtr nota;
4346
4347 /* First check that the given NOTATION was declared */
4348 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4349 if (nota == NULL)
4350 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4351
4352 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004353 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004354 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004355 value, attr->name, elem->name);
4356 ret = 0;
4357 }
4358
4359 /* Second, verify that it's among the list */
4360 while (tree != NULL) {
4361 if (xmlStrEqual(tree->name, value)) break;
4362 tree = tree->next;
4363 }
4364 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004365 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004366"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004367 value, attr->name, elem->name);
4368 ret = 0;
4369 }
4370 }
4371
4372 /* Validity Constraint: Enumeration */
4373 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4374 xmlEnumerationPtr tree = attrDecl->tree;
4375 while (tree != NULL) {
4376 if (xmlStrEqual(tree->name, value)) break;
4377 tree = tree->next;
4378 }
4379 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004380 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004381 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004382 value, attr->name, elem->name);
4383 ret = 0;
4384 }
4385 }
4386
4387 /* Fixed Attribute Default */
4388 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4389 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004390 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004391 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004392 attr->name, elem->name, attrDecl->defaultValue);
4393 ret = 0;
4394 }
4395
4396 /* Extra check for the attribute value */
4397 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4398 attrDecl->atype, value);
4399
4400 return(ret);
4401}
4402
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004403/**
4404 * xmlValidateOneNamespace:
4405 * @ctxt: the validation context
4406 * @doc: a document instance
4407 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004408 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004409 * @ns: an namespace declaration instance
4410 * @value: the attribute value (without entities processing)
4411 *
4412 * Try to validate a single namespace declaration for an element
4413 * basically it does the following checks as described by the
4414 * XML-1.0 recommendation:
4415 * - [ VC: Attribute Value Type ]
4416 * - [ VC: Fixed Attribute Default ]
4417 * - [ VC: Entity Name ]
4418 * - [ VC: Name Token ]
4419 * - [ VC: ID ]
4420 * - [ VC: IDREF ]
4421 * - [ VC: Entity Name ]
4422 * - [ VC: Notation Attributes ]
4423 *
4424 * The ID/IDREF uniqueness and matching are done separately
4425 *
4426 * returns 1 if valid or 0 otherwise
4427 */
4428
4429int
4430xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4431xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4432 /* xmlElementPtr elemDecl; */
4433 xmlAttributePtr attrDecl = NULL;
4434 int val;
4435 int ret = 1;
4436
4437 CHECK_DTD;
4438 if ((elem == NULL) || (elem->name == NULL)) return(0);
4439 if ((ns == NULL) || (ns->href == NULL)) return(0);
4440
4441 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004442 xmlChar fn[50];
4443 xmlChar *fullname;
4444
4445 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4446 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004447 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004448 return(0);
4449 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004450 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004451 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004452 ns->prefix, BAD_CAST "xmlns");
4453 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004454 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004455 ns->prefix, BAD_CAST "xmlns");
4456 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004457 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004458 BAD_CAST "xmlns");
4459 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004460 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004461 BAD_CAST "xmlns");
4462 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004463 if ((fullname != fn) && (fullname != elem->name))
4464 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004465 }
4466 if (attrDecl == NULL) {
4467 if (ns->prefix != NULL) {
4468 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4469 ns->prefix, BAD_CAST "xmlns");
4470 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4471 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4472 ns->prefix, BAD_CAST "xmlns");
4473 } else {
4474 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4475 elem->name, BAD_CAST "xmlns");
4476 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4477 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4478 elem->name, BAD_CAST "xmlns");
4479 }
4480 }
4481
4482
4483 /* Validity Constraint: Attribute Value Type */
4484 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004485 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004486 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004487 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004488 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004489 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004490 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004491 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004492 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004493 }
4494 return(0);
4495 }
4496
4497 val = xmlValidateAttributeValue(attrDecl->atype, value);
4498 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004499 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004500 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004501 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004502 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004503 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004504 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004505 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004506 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004507 }
4508 ret = 0;
4509 }
4510
4511 /* Validity constraint: Fixed Attribute Default */
4512 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4513 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004514 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004515 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004516 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4517 ns->prefix, elem->name, attrDecl->defaultValue);
4518 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004519 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004520 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004521 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004522 }
4523 ret = 0;
4524 }
4525 }
4526
4527 /* Validity Constraint: ID uniqueness */
4528 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4529 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4530 ret = 0;
4531 }
4532
4533 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4534 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4535 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4536 ret = 0;
4537 }
4538
4539 /* Validity Constraint: Notation Attributes */
4540 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4541 xmlEnumerationPtr tree = attrDecl->tree;
4542 xmlNotationPtr nota;
4543
4544 /* First check that the given NOTATION was declared */
4545 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4546 if (nota == NULL)
4547 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4548
4549 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004550 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004551 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004552 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4553 value, ns->prefix, elem->name);
4554 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004555 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004556 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004557 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004558 }
4559 ret = 0;
4560 }
4561
4562 /* Second, verify that it's among the list */
4563 while (tree != NULL) {
4564 if (xmlStrEqual(tree->name, value)) break;
4565 tree = tree->next;
4566 }
4567 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004568 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004569 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004570"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4571 value, ns->prefix, elem->name);
4572 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004573 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004574"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004575 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004576 }
4577 ret = 0;
4578 }
4579 }
4580
4581 /* Validity Constraint: Enumeration */
4582 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4583 xmlEnumerationPtr tree = attrDecl->tree;
4584 while (tree != NULL) {
4585 if (xmlStrEqual(tree->name, value)) break;
4586 tree = tree->next;
4587 }
4588 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004589 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004590 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004591"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4592 value, ns->prefix, elem->name);
4593 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004594 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004595"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004596 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004597 }
4598 ret = 0;
4599 }
4600 }
4601
4602 /* Fixed Attribute Default */
4603 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4604 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004605 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004606 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004607 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4608 ns->prefix, elem->name, attrDecl->defaultValue);
4609 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004610 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004611 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004612 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004613 }
4614 ret = 0;
4615 }
4616
4617 /* Extra check for the attribute value */
4618 if (ns->prefix != NULL) {
4619 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4620 attrDecl->atype, value);
4621 } else {
4622 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4623 attrDecl->atype, value);
4624 }
4625
4626 return(ret);
4627}
4628
Daniel Veillard118aed72002-09-24 14:13:13 +00004629#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004630/**
4631 * xmlValidateSkipIgnorable:
4632 * @ctxt: the validation context
4633 * @child: the child list
4634 *
4635 * Skip ignorable elements w.r.t. the validation process
4636 *
4637 * returns the first element to consider for validation of the content model
4638 */
4639
4640static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004641xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004642 while (child != NULL) {
4643 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004644 /* These things are ignored (skipped) during validation. */
4645 case XML_PI_NODE:
4646 case XML_COMMENT_NODE:
4647 case XML_XINCLUDE_START:
4648 case XML_XINCLUDE_END:
4649 child = child->next;
4650 break;
4651 case XML_TEXT_NODE:
4652 if (xmlIsBlankNode(child))
4653 child = child->next;
4654 else
4655 return(child);
4656 break;
4657 /* keep current node */
4658 default:
4659 return(child);
4660 }
4661 }
4662 return(child);
4663}
4664
4665/**
4666 * xmlValidateElementType:
4667 * @ctxt: the validation context
4668 *
4669 * Try to validate the content model of an element internal function
4670 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004671 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4672 * reference is found and -3 if the validation succeeded but
4673 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004674 */
4675
4676static int
4677xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004678 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004679 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004680
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004681 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004682 if ((NODE == NULL) && (CONT == NULL))
4683 return(1);
4684 if ((NODE == NULL) &&
4685 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4686 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4687 return(1);
4688 }
4689 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004690 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004691 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004692
4693 /*
4694 * We arrive here when more states need to be examined
4695 */
4696cont:
4697
4698 /*
4699 * We just recovered from a rollback generated by a possible
4700 * epsilon transition, go directly to the analysis phase
4701 */
4702 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004703 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004704 DEBUG_VALID_STATE(NODE, CONT)
4705 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004706 goto analyze;
4707 }
4708
4709 DEBUG_VALID_STATE(NODE, CONT)
4710 /*
4711 * we may have to save a backup state here. This is the equivalent
4712 * of handling epsilon transition in NFAs.
4713 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004714 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004715 ((CONT->parent == NULL) ||
4716 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004717 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004718 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004719 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004720 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004721 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4722 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004723 }
4724
4725
4726 /*
4727 * Check first if the content matches
4728 */
4729 switch (CONT->type) {
4730 case XML_ELEMENT_CONTENT_PCDATA:
4731 if (NODE == NULL) {
4732 DEBUG_VALID_MSG("pcdata failed no node");
4733 ret = 0;
4734 break;
4735 }
4736 if (NODE->type == XML_TEXT_NODE) {
4737 DEBUG_VALID_MSG("pcdata found, skip to next");
4738 /*
4739 * go to next element in the content model
4740 * skipping ignorable elems
4741 */
4742 do {
4743 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004744 NODE = xmlValidateSkipIgnorable(NODE);
4745 if ((NODE != NULL) &&
4746 (NODE->type == XML_ENTITY_REF_NODE))
4747 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004748 } while ((NODE != NULL) &&
4749 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004750 (NODE->type != XML_TEXT_NODE) &&
4751 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004752 ret = 1;
4753 break;
4754 } else {
4755 DEBUG_VALID_MSG("pcdata failed");
4756 ret = 0;
4757 break;
4758 }
4759 break;
4760 case XML_ELEMENT_CONTENT_ELEMENT:
4761 if (NODE == NULL) {
4762 DEBUG_VALID_MSG("element failed no node");
4763 ret = 0;
4764 break;
4765 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004766 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4767 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004768 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004769 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4770 ret = (CONT->prefix == NULL);
4771 } else if (CONT->prefix == NULL) {
4772 ret = 0;
4773 } else {
4774 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4775 }
4776 }
4777 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004778 DEBUG_VALID_MSG("element found, skip to next");
4779 /*
4780 * go to next element in the content model
4781 * skipping ignorable elems
4782 */
4783 do {
4784 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004785 NODE = xmlValidateSkipIgnorable(NODE);
4786 if ((NODE != NULL) &&
4787 (NODE->type == XML_ENTITY_REF_NODE))
4788 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004789 } while ((NODE != NULL) &&
4790 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004791 (NODE->type != XML_TEXT_NODE) &&
4792 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004793 } else {
4794 DEBUG_VALID_MSG("element failed");
4795 ret = 0;
4796 break;
4797 }
4798 break;
4799 case XML_ELEMENT_CONTENT_OR:
4800 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004801 * Small optimization.
4802 */
4803 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4804 if ((NODE == NULL) ||
4805 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4806 DEPTH++;
4807 CONT = CONT->c2;
4808 goto cont;
4809 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004810 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4811 ret = (CONT->c1->prefix == NULL);
4812 } else if (CONT->c1->prefix == NULL) {
4813 ret = 0;
4814 } else {
4815 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4816 }
4817 if (ret == 0) {
4818 DEPTH++;
4819 CONT = CONT->c2;
4820 goto cont;
4821 }
Daniel Veillard85349052001-04-20 13:48:21 +00004822 }
4823
4824 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004825 * save the second branch 'or' branch
4826 */
4827 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004828 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4829 OCCURS, ROLLBACK_OR) < 0)
4830 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004831 DEPTH++;
4832 CONT = CONT->c1;
4833 goto cont;
4834 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004835 /*
4836 * Small optimization.
4837 */
4838 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4839 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4840 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4841 if ((NODE == NULL) ||
4842 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4843 DEPTH++;
4844 CONT = CONT->c2;
4845 goto cont;
4846 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004847 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4848 ret = (CONT->c1->prefix == NULL);
4849 } else if (CONT->c1->prefix == NULL) {
4850 ret = 0;
4851 } else {
4852 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4853 }
4854 if (ret == 0) {
4855 DEPTH++;
4856 CONT = CONT->c2;
4857 goto cont;
4858 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004859 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004860 DEPTH++;
4861 CONT = CONT->c1;
4862 goto cont;
4863 }
4864
4865 /*
4866 * At this point handle going up in the tree
4867 */
4868 if (ret == -1) {
4869 DEBUG_VALID_MSG("error found returning");
4870 return(ret);
4871 }
4872analyze:
4873 while (CONT != NULL) {
4874 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004875 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004876 * this level.
4877 */
4878 if (ret == 0) {
4879 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004880 xmlNodePtr cur;
4881
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004882 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004883 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004884 DEBUG_VALID_MSG("Once branch failed, rollback");
4885 if (vstateVPop(ctxt) < 0 ) {
4886 DEBUG_VALID_MSG("exhaustion, failed");
4887 return(0);
4888 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004889 if (cur != ctxt->vstate->node)
4890 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004891 goto cont;
4892 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004893 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004894 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004895 DEBUG_VALID_MSG("Plus branch failed, rollback");
4896 if (vstateVPop(ctxt) < 0 ) {
4897 DEBUG_VALID_MSG("exhaustion, failed");
4898 return(0);
4899 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004900 if (cur != ctxt->vstate->node)
4901 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004902 goto cont;
4903 }
4904 DEBUG_VALID_MSG("Plus branch found");
4905 ret = 1;
4906 break;
4907 case XML_ELEMENT_CONTENT_MULT:
4908#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004909 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004910 DEBUG_VALID_MSG("Mult branch failed");
4911 } else {
4912 DEBUG_VALID_MSG("Mult branch found");
4913 }
4914#endif
4915 ret = 1;
4916 break;
4917 case XML_ELEMENT_CONTENT_OPT:
4918 DEBUG_VALID_MSG("Option branch failed");
4919 ret = 1;
4920 break;
4921 }
4922 } else {
4923 switch (CONT->ocur) {
4924 case XML_ELEMENT_CONTENT_OPT:
4925 DEBUG_VALID_MSG("Option branch succeeded");
4926 ret = 1;
4927 break;
4928 case XML_ELEMENT_CONTENT_ONCE:
4929 DEBUG_VALID_MSG("Once branch succeeded");
4930 ret = 1;
4931 break;
4932 case XML_ELEMENT_CONTENT_PLUS:
4933 if (STATE == ROLLBACK_PARENT) {
4934 DEBUG_VALID_MSG("Plus branch rollback");
4935 ret = 1;
4936 break;
4937 }
4938 if (NODE == NULL) {
4939 DEBUG_VALID_MSG("Plus branch exhausted");
4940 ret = 1;
4941 break;
4942 }
4943 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004944 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004945 goto cont;
4946 case XML_ELEMENT_CONTENT_MULT:
4947 if (STATE == ROLLBACK_PARENT) {
4948 DEBUG_VALID_MSG("Mult branch rollback");
4949 ret = 1;
4950 break;
4951 }
4952 if (NODE == NULL) {
4953 DEBUG_VALID_MSG("Mult branch exhausted");
4954 ret = 1;
4955 break;
4956 }
4957 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004958 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004959 goto cont;
4960 }
4961 }
4962 STATE = 0;
4963
4964 /*
4965 * Then act accordingly at the parent level
4966 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004967 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004968 if (CONT->parent == NULL)
4969 break;
4970
4971 switch (CONT->parent->type) {
4972 case XML_ELEMENT_CONTENT_PCDATA:
4973 DEBUG_VALID_MSG("Error: parent pcdata");
4974 return(-1);
4975 case XML_ELEMENT_CONTENT_ELEMENT:
4976 DEBUG_VALID_MSG("Error: parent element");
4977 return(-1);
4978 case XML_ELEMENT_CONTENT_OR:
4979 if (ret == 1) {
4980 DEBUG_VALID_MSG("Or succeeded");
4981 CONT = CONT->parent;
4982 DEPTH--;
4983 } else {
4984 DEBUG_VALID_MSG("Or failed");
4985 CONT = CONT->parent;
4986 DEPTH--;
4987 }
4988 break;
4989 case XML_ELEMENT_CONTENT_SEQ:
4990 if (ret == 0) {
4991 DEBUG_VALID_MSG("Sequence failed");
4992 CONT = CONT->parent;
4993 DEPTH--;
4994 } else if (CONT == CONT->parent->c1) {
4995 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4996 CONT = CONT->parent->c2;
4997 goto cont;
4998 } else {
4999 DEBUG_VALID_MSG("Sequence succeeded");
5000 CONT = CONT->parent;
5001 DEPTH--;
5002 }
5003 }
5004 }
5005 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005006 xmlNodePtr cur;
5007
5008 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005009 DEBUG_VALID_MSG("Failed, remaining input, rollback");
5010 if (vstateVPop(ctxt) < 0 ) {
5011 DEBUG_VALID_MSG("exhaustion, failed");
5012 return(0);
5013 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005014 if (cur != ctxt->vstate->node)
5015 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005016 goto cont;
5017 }
5018 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005019 xmlNodePtr cur;
5020
5021 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005022 DEBUG_VALID_MSG("Failure, rollback");
5023 if (vstateVPop(ctxt) < 0 ) {
5024 DEBUG_VALID_MSG("exhaustion, failed");
5025 return(0);
5026 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005027 if (cur != ctxt->vstate->node)
5028 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005029 goto cont;
5030 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005031 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005032}
Daniel Veillard23e73572002-09-19 19:56:43 +00005033#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005034
5035/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00005036 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005037 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00005038 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005039 * @content: An element
5040 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5041 *
5042 * This will dump the list of elements to the buffer
5043 * Intended just for the debug routine
5044 */
5045static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00005046xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005047 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00005048 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005049
5050 if (node == NULL) return;
5051 if (glob) strcat(buf, "(");
5052 cur = node;
5053 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005054 len = strlen(buf);
5055 if (size - len < 50) {
5056 if ((size - len > 4) && (buf[len - 1] != '.'))
5057 strcat(buf, " ...");
5058 return;
5059 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005060 switch (cur->type) {
5061 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005062 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005063 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005064 if ((size - len > 4) && (buf[len - 1] != '.'))
5065 strcat(buf, " ...");
5066 return;
5067 }
5068 strcat(buf, (char *) cur->ns->prefix);
5069 strcat(buf, ":");
5070 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005071 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005072 if ((size - len > 4) && (buf[len - 1] != '.'))
5073 strcat(buf, " ...");
5074 return;
5075 }
5076 strcat(buf, (char *) cur->name);
5077 if (cur->next != NULL)
5078 strcat(buf, " ");
5079 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005080 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005081 if (xmlIsBlankNode(cur))
5082 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005083 case XML_CDATA_SECTION_NODE:
5084 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005085 strcat(buf, "CDATA");
5086 if (cur->next != NULL)
5087 strcat(buf, " ");
5088 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005089 case XML_ATTRIBUTE_NODE:
5090 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005091#ifdef LIBXML_DOCB_ENABLED
5092 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005093#endif
5094 case XML_HTML_DOCUMENT_NODE:
5095 case XML_DOCUMENT_TYPE_NODE:
5096 case XML_DOCUMENT_FRAG_NODE:
5097 case XML_NOTATION_NODE:
5098 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005099 strcat(buf, "???");
5100 if (cur->next != NULL)
5101 strcat(buf, " ");
5102 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005103 case XML_ENTITY_NODE:
5104 case XML_PI_NODE:
5105 case XML_DTD_NODE:
5106 case XML_COMMENT_NODE:
5107 case XML_ELEMENT_DECL:
5108 case XML_ATTRIBUTE_DECL:
5109 case XML_ENTITY_DECL:
5110 case XML_XINCLUDE_START:
5111 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005112 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005113 }
5114 cur = cur->next;
5115 }
5116 if (glob) strcat(buf, ")");
5117}
5118
5119/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005120 * xmlValidateElementContent:
5121 * @ctxt: the validation context
5122 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005123 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005124 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005125 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005126 *
5127 * Try to validate the content model of an element
5128 *
5129 * returns 1 if valid or 0 if not and -1 in case of error
5130 */
5131
5132static int
5133xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005134 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00005135 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00005136#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00005137 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00005138#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00005139 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005140 xmlElementContentPtr cont;
5141 const xmlChar *name;
5142
5143 if (elemDecl == NULL)
5144 return(-1);
5145 cont = elemDecl->content;
5146 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005147
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005148#ifdef LIBXML_REGEXP_ENABLED
5149 /* Build the regexp associated to the content model */
5150 if (elemDecl->contModel == NULL)
5151 ret = xmlValidBuildContentModel(ctxt, elemDecl);
5152 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005153 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005154 } else {
5155 xmlRegExecCtxtPtr exec;
5156
Daniel Veillardec498e12003-02-05 11:01:50 +00005157 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5158 return(-1);
5159 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005160 ctxt->nodeMax = 0;
5161 ctxt->nodeNr = 0;
5162 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005163 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5164 if (exec != NULL) {
5165 cur = child;
5166 while (cur != NULL) {
5167 switch (cur->type) {
5168 case XML_ENTITY_REF_NODE:
5169 /*
5170 * Push the current node to be able to roll back
5171 * and process within the entity
5172 */
5173 if ((cur->children != NULL) &&
5174 (cur->children->children != NULL)) {
5175 nodeVPush(ctxt, cur);
5176 cur = cur->children->children;
5177 continue;
5178 }
5179 break;
5180 case XML_TEXT_NODE:
5181 if (xmlIsBlankNode(cur))
5182 break;
5183 ret = 0;
5184 goto fail;
5185 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00005186 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005187 ret = 0;
5188 goto fail;
5189 case XML_ELEMENT_NODE:
5190 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005191 xmlChar fn[50];
5192 xmlChar *fullname;
5193
5194 fullname = xmlBuildQName(cur->name,
5195 cur->ns->prefix, fn, 50);
5196 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005197 ret = -1;
5198 goto fail;
5199 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005200 ret = xmlRegExecPushString(exec, fullname, NULL);
5201 if ((fullname != fn) && (fullname != cur->name))
5202 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005203 } else {
5204 ret = xmlRegExecPushString(exec, cur->name, NULL);
5205 }
5206 break;
5207 default:
5208 break;
5209 }
5210 /*
5211 * Switch to next element
5212 */
5213 cur = cur->next;
5214 while (cur == NULL) {
5215 cur = nodeVPop(ctxt);
5216 if (cur == NULL)
5217 break;
5218 cur = cur->next;
5219 }
5220 }
5221 ret = xmlRegExecPushString(exec, NULL, NULL);
5222fail:
5223 xmlRegFreeExecCtxt(exec);
5224 }
5225 }
5226#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005227 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005228 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005229 */
5230 ctxt->vstateMax = 8;
5231 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5232 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5233 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005234 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005235 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005236 }
5237 /*
5238 * The first entry in the stack is reserved to the current state
5239 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005240 ctxt->nodeMax = 0;
5241 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005242 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005243 ctxt->vstate = &ctxt->vstateTab[0];
5244 ctxt->vstateNr = 1;
5245 CONT = cont;
5246 NODE = child;
5247 DEPTH = 0;
5248 OCCURS = 0;
5249 STATE = 0;
5250 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005251 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005252 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5253 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005254 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005255 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005256 /*
5257 * An entities reference appeared at this level.
5258 * Buid a minimal representation of this node content
5259 * sufficient to run the validation process on it
5260 */
5261 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005262 cur = child;
5263 while (cur != NULL) {
5264 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005265 case XML_ENTITY_REF_NODE:
5266 /*
5267 * Push the current node to be able to roll back
5268 * and process within the entity
5269 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005270 if ((cur->children != NULL) &&
5271 (cur->children->children != NULL)) {
5272 nodeVPush(ctxt, cur);
5273 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005274 continue;
5275 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005276 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005277 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005278 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005279 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005280 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005281 case XML_CDATA_SECTION_NODE:
5282 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005283 case XML_ELEMENT_NODE:
5284 /*
5285 * Allocate a new node and minimally fills in
5286 * what's required
5287 */
5288 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5289 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005290 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005291 xmlFreeNodeList(repl);
5292 ret = -1;
5293 goto done;
5294 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005295 tmp->type = cur->type;
5296 tmp->name = cur->name;
5297 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005298 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005299 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005300 if (repl == NULL)
5301 repl = last = tmp;
5302 else {
5303 last->next = tmp;
5304 last = tmp;
5305 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005306 if (cur->type == XML_CDATA_SECTION_NODE) {
5307 /*
5308 * E59 spaces in CDATA does not match the
5309 * nonterminal S
5310 */
5311 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5312 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005313 break;
5314 default:
5315 break;
5316 }
5317 /*
5318 * Switch to next element
5319 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005320 cur = cur->next;
5321 while (cur == NULL) {
5322 cur = nodeVPop(ctxt);
5323 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005324 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005325 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005326 }
5327 }
5328
5329 /*
5330 * Relaunch the validation
5331 */
5332 ctxt->vstate = &ctxt->vstateTab[0];
5333 ctxt->vstateNr = 1;
5334 CONT = cont;
5335 NODE = repl;
5336 DEPTH = 0;
5337 OCCURS = 0;
5338 STATE = 0;
5339 ret = xmlValidateElementType(ctxt);
5340 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005341#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005342 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005343 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5344 char expr[5000];
5345 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005346
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005347 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005348 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005349 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005350#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005351 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005352 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005353 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005354#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005355 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005356
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005357 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005358 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5359 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5360 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005361 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005362 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5363 "Element content does not follow the DTD, expecting %s, got %s\n",
5364 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005365 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005366 } else {
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,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005369 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005370 name, NULL, NULL);
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\n",
5374 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005375 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005376 }
5377 ret = 0;
5378 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005379 if (ret == -3)
5380 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005381
Daniel Veillard23e73572002-09-19 19:56:43 +00005382#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005383done:
5384 /*
5385 * Deallocate the copy if done, and free up the validation stack
5386 */
5387 while (repl != NULL) {
5388 tmp = repl->next;
5389 xmlFree(repl);
5390 repl = tmp;
5391 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005392 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005393 if (ctxt->vstateTab != NULL) {
5394 xmlFree(ctxt->vstateTab);
5395 ctxt->vstateTab = NULL;
5396 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005397#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005398 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005399 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005400 if (ctxt->nodeTab != NULL) {
5401 xmlFree(ctxt->nodeTab);
5402 ctxt->nodeTab = NULL;
5403 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005404 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005405
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005406}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005407
Owen Taylor3473f882001-02-23 17:55:21 +00005408/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005409 * xmlValidateCdataElement:
5410 * @ctxt: the validation context
5411 * @doc: a document instance
5412 * @elem: an element instance
5413 *
5414 * Check that an element follows #CDATA
5415 *
5416 * returns 1 if valid or 0 otherwise
5417 */
5418static int
5419xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5420 xmlNodePtr elem) {
5421 int ret = 1;
5422 xmlNodePtr cur, child;
5423
Daniel Veillardceb09b92002-10-04 11:46:37 +00005424 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005425 return(0);
5426
5427 child = elem->children;
5428
5429 cur = child;
5430 while (cur != NULL) {
5431 switch (cur->type) {
5432 case XML_ENTITY_REF_NODE:
5433 /*
5434 * Push the current node to be able to roll back
5435 * and process within the entity
5436 */
5437 if ((cur->children != NULL) &&
5438 (cur->children->children != NULL)) {
5439 nodeVPush(ctxt, cur);
5440 cur = cur->children->children;
5441 continue;
5442 }
5443 break;
5444 case XML_COMMENT_NODE:
5445 case XML_PI_NODE:
5446 case XML_TEXT_NODE:
5447 case XML_CDATA_SECTION_NODE:
5448 break;
5449 default:
5450 ret = 0;
5451 goto done;
5452 }
5453 /*
5454 * Switch to next element
5455 */
5456 cur = cur->next;
5457 while (cur == NULL) {
5458 cur = nodeVPop(ctxt);
5459 if (cur == NULL)
5460 break;
5461 cur = cur->next;
5462 }
5463 }
5464done:
5465 ctxt->nodeMax = 0;
5466 ctxt->nodeNr = 0;
5467 if (ctxt->nodeTab != NULL) {
5468 xmlFree(ctxt->nodeTab);
5469 ctxt->nodeTab = NULL;
5470 }
5471 return(ret);
5472}
5473
5474/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005475 * xmlValidateCheckMixed:
5476 * @ctxt: the validation context
5477 * @cont: the mixed content model
5478 * @qname: the qualified name as appearing in the serialization
5479 *
5480 * Check if the given node is part of the content model.
5481 *
5482 * Returns 1 if yes, 0 if no, -1 in case of error
5483 */
5484static int
William M. Brackedb65a72004-02-06 07:36:04 +00005485xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005486 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005487 const xmlChar *name;
5488 int plen;
5489 name = xmlSplitQName3(qname, &plen);
5490
5491 if (name == NULL) {
5492 while (cont != NULL) {
5493 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5494 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5495 return(1);
5496 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5497 (cont->c1 != NULL) &&
5498 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5499 if ((cont->c1->prefix == NULL) &&
5500 (xmlStrEqual(cont->c1->name, qname)))
5501 return(1);
5502 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5503 (cont->c1 == NULL) ||
5504 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005505 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5506 "Internal: MIXED struct corrupted\n",
5507 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005508 break;
5509 }
5510 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005511 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005512 } else {
5513 while (cont != NULL) {
5514 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5515 if ((cont->prefix != NULL) &&
5516 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5517 (xmlStrEqual(cont->name, name)))
5518 return(1);
5519 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5520 (cont->c1 != NULL) &&
5521 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5522 if ((cont->c1->prefix != NULL) &&
5523 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5524 (xmlStrEqual(cont->c1->name, name)))
5525 return(1);
5526 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5527 (cont->c1 == NULL) ||
5528 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005529 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5530 "Internal: MIXED struct corrupted\n",
5531 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005532 break;
5533 }
5534 cont = cont->c2;
5535 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005536 }
5537 return(0);
5538}
5539
5540/**
5541 * xmlValidGetElemDecl:
5542 * @ctxt: the validation context
5543 * @doc: a document instance
5544 * @elem: an element instance
5545 * @extsubset: pointer, (out) indicate if the declaration was found
5546 * in the external subset.
5547 *
5548 * Finds a declaration associated to an element in the document.
5549 *
5550 * returns the pointer to the declaration or NULL if not found.
5551 */
5552static xmlElementPtr
5553xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5554 xmlNodePtr elem, int *extsubset) {
5555 xmlElementPtr elemDecl = NULL;
5556 const xmlChar *prefix = NULL;
5557
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005558 if ((ctxt == NULL) || (doc == NULL) ||
5559 (elem == NULL) || (elem->name == NULL))
5560 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005561 if (extsubset != NULL)
5562 *extsubset = 0;
5563
5564 /*
5565 * Fetch the declaration for the qualified name
5566 */
5567 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5568 prefix = elem->ns->prefix;
5569
5570 if (prefix != NULL) {
5571 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5572 elem->name, prefix);
5573 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5574 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5575 elem->name, prefix);
5576 if ((elemDecl != NULL) && (extsubset != NULL))
5577 *extsubset = 1;
5578 }
5579 }
5580
5581 /*
5582 * Fetch the declaration for the non qualified name
5583 * This is "non-strict" validation should be done on the
5584 * full QName but in that case being flexible makes sense.
5585 */
5586 if (elemDecl == NULL) {
5587 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5588 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5589 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5590 if ((elemDecl != NULL) && (extsubset != NULL))
5591 *extsubset = 1;
5592 }
5593 }
5594 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005595 xmlErrValidNode(ctxt, elem,
5596 XML_DTD_UNKNOWN_ELEM,
5597 "No declaration for element %s\n",
5598 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005599 }
5600 return(elemDecl);
5601}
5602
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005603#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005604/**
5605 * xmlValidatePushElement:
5606 * @ctxt: the validation context
5607 * @doc: a document instance
5608 * @elem: an element instance
5609 * @qname: the qualified name as appearing in the serialization
5610 *
5611 * Push a new element start on the validation stack.
5612 *
5613 * returns 1 if no validation problem was found or 0 otherwise
5614 */
5615int
5616xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5617 xmlNodePtr elem, const xmlChar *qname) {
5618 int ret = 1;
5619 xmlElementPtr eDecl;
5620 int extsubset = 0;
5621
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005622 if (ctxt == NULL)
5623 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005624/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005625 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5626 xmlValidStatePtr state = ctxt->vstate;
5627 xmlElementPtr elemDecl;
5628
5629 /*
5630 * Check the new element agaisnt the content model of the new elem.
5631 */
5632 if (state->elemDecl != NULL) {
5633 elemDecl = state->elemDecl;
5634
5635 switch(elemDecl->etype) {
5636 case XML_ELEMENT_TYPE_UNDEFINED:
5637 ret = 0;
5638 break;
5639 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005640 xmlErrValidNode(ctxt, state->node,
5641 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005642 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005643 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005644 ret = 0;
5645 break;
5646 case XML_ELEMENT_TYPE_ANY:
5647 /* I don't think anything is required then */
5648 break;
5649 case XML_ELEMENT_TYPE_MIXED:
5650 /* simple case of declared as #PCDATA */
5651 if ((elemDecl->content != NULL) &&
5652 (elemDecl->content->type ==
5653 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005654 xmlErrValidNode(ctxt, state->node,
5655 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005656 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005657 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005658 ret = 0;
5659 } else {
5660 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5661 qname);
5662 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005663 xmlErrValidNode(ctxt, state->node,
5664 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005665 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005666 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005667 }
5668 }
5669 break;
5670 case XML_ELEMENT_TYPE_ELEMENT:
5671 /*
5672 * TODO:
5673 * VC: Standalone Document Declaration
5674 * - element types with element content, if white space
5675 * occurs directly within any instance of those types.
5676 */
5677 if (state->exec != NULL) {
5678 ret = xmlRegExecPushString(state->exec, qname, NULL);
5679 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005680 xmlErrValidNode(ctxt, state->node,
5681 XML_DTD_CONTENT_MODEL,
5682 "Element %s content does not follow the DTD, Misplaced %s\n",
5683 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005684 ret = 0;
5685 } else {
5686 ret = 1;
5687 }
5688 }
5689 break;
5690 }
5691 }
5692 }
5693 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5694 vstateVPush(ctxt, eDecl, elem);
5695 return(ret);
5696}
5697
5698/**
5699 * xmlValidatePushCData:
5700 * @ctxt: the validation context
5701 * @data: some character data read
5702 * @len: the lenght of the data
5703 *
5704 * check the CData parsed for validation in the current stack
5705 *
5706 * returns 1 if no validation problem was found or 0 otherwise
5707 */
5708int
5709xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5710 int ret = 1;
5711
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005712/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005713 if (ctxt == NULL)
5714 return(0);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005715 if (len <= 0)
5716 return(ret);
5717 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5718 xmlValidStatePtr state = ctxt->vstate;
5719 xmlElementPtr elemDecl;
5720
5721 /*
5722 * Check the new element agaisnt the content model of the new elem.
5723 */
5724 if (state->elemDecl != NULL) {
5725 elemDecl = state->elemDecl;
5726
5727 switch(elemDecl->etype) {
5728 case XML_ELEMENT_TYPE_UNDEFINED:
5729 ret = 0;
5730 break;
5731 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005732 xmlErrValidNode(ctxt, state->node,
5733 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005734 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005735 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005736 ret = 0;
5737 break;
5738 case XML_ELEMENT_TYPE_ANY:
5739 break;
5740 case XML_ELEMENT_TYPE_MIXED:
5741 break;
5742 case XML_ELEMENT_TYPE_ELEMENT:
5743 if (len > 0) {
5744 int i;
5745
5746 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005747 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005748 xmlErrValidNode(ctxt, state->node,
5749 XML_DTD_CONTENT_MODEL,
5750 "Element %s content does not follow the DTD, Text not allowed\n",
5751 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005752 ret = 0;
5753 goto done;
5754 }
5755 }
5756 /*
5757 * TODO:
5758 * VC: Standalone Document Declaration
5759 * element types with element content, if white space
5760 * occurs directly within any instance of those types.
5761 */
5762 }
5763 break;
5764 }
5765 }
5766 }
5767done:
5768 return(ret);
5769}
5770
5771/**
5772 * xmlValidatePopElement:
5773 * @ctxt: the validation context
5774 * @doc: a document instance
5775 * @elem: an element instance
5776 * @qname: the qualified name as appearing in the serialization
5777 *
5778 * Pop the element end from the validation stack.
5779 *
5780 * returns 1 if no validation problem was found or 0 otherwise
5781 */
5782int
5783xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005784 xmlNodePtr elem ATTRIBUTE_UNUSED,
5785 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005786 int ret = 1;
5787
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005788 if (ctxt == NULL)
5789 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005790/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005791 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5792 xmlValidStatePtr state = ctxt->vstate;
5793 xmlElementPtr elemDecl;
5794
5795 /*
5796 * Check the new element agaisnt the content model of the new elem.
5797 */
5798 if (state->elemDecl != NULL) {
5799 elemDecl = state->elemDecl;
5800
5801 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5802 if (state->exec != NULL) {
5803 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5804 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005805 xmlErrValidNode(ctxt, state->node,
5806 XML_DTD_CONTENT_MODEL,
5807 "Element %s content does not follow the DTD, Expecting more child\n",
5808 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005809 } else {
5810 /*
5811 * previous validation errors should not generate
5812 * a new one here
5813 */
5814 ret = 1;
5815 }
5816 }
5817 }
5818 }
5819 vstateVPop(ctxt);
5820 }
5821 return(ret);
5822}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005823#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005824
5825/**
Owen Taylor3473f882001-02-23 17:55:21 +00005826 * xmlValidateOneElement:
5827 * @ctxt: the validation context
5828 * @doc: a document instance
5829 * @elem: an element instance
5830 *
5831 * Try to validate a single element and it's attributes,
5832 * basically it does the following checks as described by the
5833 * XML-1.0 recommendation:
5834 * - [ VC: Element Valid ]
5835 * - [ VC: Required Attribute ]
5836 * Then call xmlValidateOneAttribute() for each attribute present.
5837 *
5838 * The ID/IDREF checkings are done separately
5839 *
5840 * returns 1 if valid or 0 otherwise
5841 */
5842
5843int
5844xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5845 xmlNodePtr elem) {
5846 xmlElementPtr elemDecl = NULL;
5847 xmlElementContentPtr cont;
5848 xmlAttributePtr attr;
5849 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005850 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005851 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005852 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005853
5854 CHECK_DTD;
5855
5856 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005857 switch (elem->type) {
5858 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005859 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5860 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005861 return(0);
5862 case XML_TEXT_NODE:
5863 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005864 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5865 "Text element has children !\n",
5866 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005867 return(0);
5868 }
Owen Taylor3473f882001-02-23 17:55:21 +00005869 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005870 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5871 "Text element has namespace !\n",
5872 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005873 return(0);
5874 }
Owen Taylor3473f882001-02-23 17:55:21 +00005875 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005876 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5877 "Text element has no content !\n",
5878 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005879 return(0);
5880 }
5881 return(1);
5882 case XML_XINCLUDE_START:
5883 case XML_XINCLUDE_END:
5884 return(1);
5885 case XML_CDATA_SECTION_NODE:
5886 case XML_ENTITY_REF_NODE:
5887 case XML_PI_NODE:
5888 case XML_COMMENT_NODE:
5889 return(1);
5890 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005891 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5892 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005893 return(0);
5894 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005895 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5896 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005897 return(0);
5898 case XML_DOCUMENT_NODE:
5899 case XML_DOCUMENT_TYPE_NODE:
5900 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005901 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5902 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005903 return(0);
5904 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005905 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5906 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005907 return(0);
5908 case XML_ELEMENT_NODE:
5909 break;
5910 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005911 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5912 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005913 return(0);
5914 }
Owen Taylor3473f882001-02-23 17:55:21 +00005915
5916 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005917 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005918 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005919 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5920 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005921 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005922
Daniel Veillardea7751d2002-12-20 00:16:24 +00005923 /*
5924 * If vstateNr is not zero that means continuous validation is
5925 * activated, do not try to check the content model at that level.
5926 */
5927 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005928 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005929 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005930 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005931 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5932 "No declaration for element %s\n",
5933 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005934 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005935 case XML_ELEMENT_TYPE_EMPTY:
5936 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005937 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005938 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005939 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005940 ret = 0;
5941 }
5942 break;
5943 case XML_ELEMENT_TYPE_ANY:
5944 /* I don't think anything is required then */
5945 break;
5946 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005947
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005948 /* simple case of declared as #PCDATA */
5949 if ((elemDecl->content != NULL) &&
5950 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5951 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5952 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005953 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005954 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005955 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005956 }
5957 break;
5958 }
Owen Taylor3473f882001-02-23 17:55:21 +00005959 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005960 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005961 while (child != NULL) {
5962 if (child->type == XML_ELEMENT_NODE) {
5963 name = child->name;
5964 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005965 xmlChar fn[50];
5966 xmlChar *fullname;
5967
5968 fullname = xmlBuildQName(child->name, child->ns->prefix,
5969 fn, 50);
5970 if (fullname == NULL)
5971 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005972 cont = elemDecl->content;
5973 while (cont != NULL) {
5974 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005975 if (xmlStrEqual(cont->name, fullname))
5976 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005977 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5978 (cont->c1 != NULL) &&
5979 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005980 if (xmlStrEqual(cont->c1->name, fullname))
5981 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005982 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5983 (cont->c1 == NULL) ||
5984 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005985 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5986 "Internal: MIXED struct corrupted\n",
5987 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005988 break;
5989 }
5990 cont = cont->c2;
5991 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005992 if ((fullname != fn) && (fullname != child->name))
5993 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005994 if (cont != NULL)
5995 goto child_ok;
5996 }
5997 cont = elemDecl->content;
5998 while (cont != NULL) {
5999 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6000 if (xmlStrEqual(cont->name, name)) break;
6001 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6002 (cont->c1 != NULL) &&
6003 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
6004 if (xmlStrEqual(cont->c1->name, name)) break;
6005 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6006 (cont->c1 == NULL) ||
6007 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006008 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
6009 "Internal: MIXED struct corrupted\n",
6010 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006011 break;
6012 }
6013 cont = cont->c2;
6014 }
6015 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006016 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006017 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006018 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006019 ret = 0;
6020 }
6021 }
6022child_ok:
6023 child = child->next;
6024 }
6025 break;
6026 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006027 if ((doc->standalone == 1) && (extsubset == 1)) {
6028 /*
6029 * VC: Standalone Document Declaration
6030 * - element types with element content, if white space
6031 * occurs directly within any instance of those types.
6032 */
6033 child = elem->children;
6034 while (child != NULL) {
6035 if (child->type == XML_TEXT_NODE) {
6036 const xmlChar *content = child->content;
6037
William M. Brack76e95df2003-10-18 16:20:14 +00006038 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006039 content++;
6040 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006041 xmlErrValidNode(ctxt, elem,
6042 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006043"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006044 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006045 ret = 0;
6046 break;
6047 }
6048 }
6049 child =child->next;
6050 }
6051 }
Owen Taylor3473f882001-02-23 17:55:21 +00006052 child = elem->children;
6053 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00006054 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006055 if (tmp <= 0)
6056 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006057 break;
6058 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00006059 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00006060
6061 /* [ VC: Required Attribute ] */
6062 attr = elemDecl->attributes;
6063 while (attr != NULL) {
6064 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006065 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006066
Daniel Veillarde4301c82002-02-13 13:32:35 +00006067 if ((attr->prefix == NULL) &&
6068 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6069 xmlNsPtr ns;
6070
6071 ns = elem->nsDef;
6072 while (ns != NULL) {
6073 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006074 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006075 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006076 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006077 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6078 xmlNsPtr ns;
6079
6080 ns = elem->nsDef;
6081 while (ns != NULL) {
6082 if (xmlStrEqual(attr->name, ns->prefix))
6083 goto found;
6084 ns = ns->next;
6085 }
6086 } else {
6087 xmlAttrPtr attrib;
6088
6089 attrib = elem->properties;
6090 while (attrib != NULL) {
6091 if (xmlStrEqual(attrib->name, attr->name)) {
6092 if (attr->prefix != NULL) {
6093 xmlNsPtr nameSpace = attrib->ns;
6094
6095 if (nameSpace == NULL)
6096 nameSpace = elem->ns;
6097 /*
6098 * qualified names handling is problematic, having a
6099 * different prefix should be possible but DTDs don't
6100 * allow to define the URI instead of the prefix :-(
6101 */
6102 if (nameSpace == NULL) {
6103 if (qualified < 0)
6104 qualified = 0;
6105 } else if (!xmlStrEqual(nameSpace->prefix,
6106 attr->prefix)) {
6107 if (qualified < 1)
6108 qualified = 1;
6109 } else
6110 goto found;
6111 } else {
6112 /*
6113 * We should allow applications to define namespaces
6114 * for their application even if the DTD doesn't
6115 * carry one, otherwise, basically we would always
6116 * break.
6117 */
6118 goto found;
6119 }
6120 }
6121 attrib = attrib->next;
6122 }
Owen Taylor3473f882001-02-23 17:55:21 +00006123 }
6124 if (qualified == -1) {
6125 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006126 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006127 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006128 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006129 ret = 0;
6130 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006131 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006132 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00006133 elem->name, attr->prefix,attr->name);
6134 ret = 0;
6135 }
6136 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006137 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006138 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006139 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006140 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006141 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006142 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006143 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006144 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006145 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
6146 /*
6147 * Special tests checking #FIXED namespace declarations
6148 * have the right value since this is not done as an
6149 * attribute checking
6150 */
6151 if ((attr->prefix == NULL) &&
6152 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6153 xmlNsPtr ns;
6154
6155 ns = elem->nsDef;
6156 while (ns != NULL) {
6157 if (ns->prefix == NULL) {
6158 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006159 xmlErrValidNode(ctxt, elem,
6160 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00006161 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006162 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006163 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006164 }
6165 goto found;
6166 }
6167 ns = ns->next;
6168 }
6169 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6170 xmlNsPtr ns;
6171
6172 ns = elem->nsDef;
6173 while (ns != NULL) {
6174 if (xmlStrEqual(attr->name, ns->prefix)) {
6175 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006176 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006177 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006178 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006179 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006180 }
6181 goto found;
6182 }
6183 ns = ns->next;
6184 }
6185 }
Owen Taylor3473f882001-02-23 17:55:21 +00006186 }
6187found:
6188 attr = attr->nexth;
6189 }
6190 return(ret);
6191}
6192
6193/**
6194 * xmlValidateRoot:
6195 * @ctxt: the validation context
6196 * @doc: a document instance
6197 *
6198 * Try to validate a the root element
6199 * basically it does the following check as described by the
6200 * XML-1.0 recommendation:
6201 * - [ VC: Root Element Type ]
6202 * it doesn't try to recurse or apply other check to the element
6203 *
6204 * returns 1 if valid or 0 otherwise
6205 */
6206
6207int
6208xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6209 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006210 int ret;
6211
Owen Taylor3473f882001-02-23 17:55:21 +00006212 if (doc == NULL) return(0);
6213
6214 root = xmlDocGetRootElement(doc);
6215 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006216 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6217 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006218 return(0);
6219 }
6220
6221 /*
6222 * When doing post validation against a separate DTD, those may
6223 * no internal subset has been generated
6224 */
6225 if ((doc->intSubset != NULL) &&
6226 (doc->intSubset->name != NULL)) {
6227 /*
6228 * Check first the document root against the NQName
6229 */
6230 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6231 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006232 xmlChar fn[50];
6233 xmlChar *fullname;
6234
6235 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6236 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006237 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006238 return(0);
6239 }
6240 ret = xmlStrEqual(doc->intSubset->name, fullname);
6241 if ((fullname != fn) && (fullname != root->name))
6242 xmlFree(fullname);
6243 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006244 goto name_ok;
6245 }
6246 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6247 (xmlStrEqual(root->name, BAD_CAST "html")))
6248 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006249 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6250 "root and DTD name do not match '%s' and '%s'\n",
6251 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006252 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006253 }
6254 }
6255name_ok:
6256 return(1);
6257}
6258
6259
6260/**
6261 * xmlValidateElement:
6262 * @ctxt: the validation context
6263 * @doc: a document instance
6264 * @elem: an element instance
6265 *
6266 * Try to validate the subtree under an element
6267 *
6268 * returns 1 if valid or 0 otherwise
6269 */
6270
6271int
6272xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6273 xmlNodePtr child;
6274 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006275 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006276 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006277 int ret = 1;
6278
6279 if (elem == NULL) return(0);
6280
6281 /*
6282 * XInclude elements were added after parsing in the infoset,
6283 * they don't really mean anything validation wise.
6284 */
6285 if ((elem->type == XML_XINCLUDE_START) ||
6286 (elem->type == XML_XINCLUDE_END))
6287 return(1);
6288
6289 CHECK_DTD;
6290
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006291 /*
6292 * Entities references have to be handled separately
6293 */
6294 if (elem->type == XML_ENTITY_REF_NODE) {
6295 return(1);
6296 }
6297
Owen Taylor3473f882001-02-23 17:55:21 +00006298 ret &= xmlValidateOneElement(ctxt, doc, elem);
Daniel Veillard8874b942005-08-25 13:19:21 +00006299 if (elem->type == XML_ELEMENT_NODE) {
6300 attr = elem->properties;
6301 while (attr != NULL) {
6302 value = xmlNodeListGetString(doc, attr->children, 0);
6303 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6304 if (value != NULL)
6305 xmlFree((char *)value);
6306 attr= attr->next;
6307 }
6308 ns = elem->nsDef;
6309 while (ns != NULL) {
6310 if (elem->ns == NULL)
6311 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6312 ns, ns->href);
6313 else
6314 ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6315 elem->ns->prefix, ns, ns->href);
6316 ns = ns->next;
6317 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006318 }
Owen Taylor3473f882001-02-23 17:55:21 +00006319 child = elem->children;
6320 while (child != NULL) {
6321 ret &= xmlValidateElement(ctxt, doc, child);
6322 child = child->next;
6323 }
6324
6325 return(ret);
6326}
6327
Daniel Veillard8730c562001-02-26 10:49:57 +00006328/**
6329 * xmlValidateRef:
6330 * @ref: A reference to be validated
6331 * @ctxt: Validation context
6332 * @name: Name of ID we are searching for
6333 *
6334 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006335static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006336xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006337 const xmlChar *name) {
6338 xmlAttrPtr id;
6339 xmlAttrPtr attr;
6340
6341 if (ref == NULL)
6342 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006343 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006344 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006345 attr = ref->attr;
6346 if (attr == NULL) {
6347 xmlChar *dup, *str = NULL, *cur, save;
6348
6349 dup = xmlStrdup(name);
6350 if (dup == NULL) {
6351 ctxt->valid = 0;
6352 return;
6353 }
6354 cur = dup;
6355 while (*cur != 0) {
6356 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006357 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006358 save = *cur;
6359 *cur = 0;
6360 id = xmlGetID(ctxt->doc, str);
6361 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006362 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006363 "attribute %s line %d references an unknown ID \"%s\"\n",
6364 ref->name, ref->lineno, str);
6365 ctxt->valid = 0;
6366 }
6367 if (save == 0)
6368 break;
6369 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006370 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006371 }
6372 xmlFree(dup);
6373 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006374 id = xmlGetID(ctxt->doc, name);
6375 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006376 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006377 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006378 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006379 ctxt->valid = 0;
6380 }
6381 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6382 xmlChar *dup, *str = NULL, *cur, save;
6383
6384 dup = xmlStrdup(name);
6385 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006386 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006387 ctxt->valid = 0;
6388 return;
6389 }
6390 cur = dup;
6391 while (*cur != 0) {
6392 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006393 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006394 save = *cur;
6395 *cur = 0;
6396 id = xmlGetID(ctxt->doc, str);
6397 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006398 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006399 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006400 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006401 ctxt->valid = 0;
6402 }
6403 if (save == 0)
6404 break;
6405 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006406 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006407 }
6408 xmlFree(dup);
6409 }
6410}
6411
6412/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006413 * xmlWalkValidateList:
6414 * @data: Contents of current link
6415 * @user: Value supplied by the user
6416 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006417 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006418 */
6419static int
6420xmlWalkValidateList(const void *data, const void *user)
6421{
6422 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6423 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6424 return 1;
6425}
6426
6427/**
6428 * xmlValidateCheckRefCallback:
6429 * @ref_list: List of references
6430 * @ctxt: Validation context
6431 * @name: Name of ID we are searching for
6432 *
6433 */
6434static void
6435xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6436 const xmlChar *name) {
6437 xmlValidateMemo memo;
6438
6439 if (ref_list == NULL)
6440 return;
6441 memo.ctxt = ctxt;
6442 memo.name = name;
6443
6444 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6445
6446}
6447
6448/**
Owen Taylor3473f882001-02-23 17:55:21 +00006449 * xmlValidateDocumentFinal:
6450 * @ctxt: the validation context
6451 * @doc: a document instance
6452 *
6453 * Does the final step for the document validation once all the
6454 * incremental validation steps have been completed
6455 *
6456 * basically it does the following checks described by the XML Rec
6457 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006458 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006459 *
6460 * returns 1 if valid or 0 otherwise
6461 */
6462
6463int
6464xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6465 xmlRefTablePtr table;
6466
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006467 if (ctxt == NULL)
6468 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006469 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006470 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6471 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006472 return(0);
6473 }
6474
6475 /*
6476 * Check all the NOTATION/NOTATIONS attributes
6477 */
6478 /*
6479 * Check all the ENTITY/ENTITIES attributes definition for validity
6480 */
6481 /*
6482 * Check all the IDREF/IDREFS attributes definition for validity
6483 */
6484 table = (xmlRefTablePtr) doc->refs;
6485 ctxt->doc = doc;
6486 ctxt->valid = 1;
6487 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6488 return(ctxt->valid);
6489}
6490
6491/**
6492 * xmlValidateDtd:
6493 * @ctxt: the validation context
6494 * @doc: a document instance
6495 * @dtd: a dtd instance
6496 *
6497 * Try to validate the document against the dtd instance
6498 *
William M. Brack367df6e2004-10-23 18:14:36 +00006499 * Basically it does check all the definitions in the DtD.
6500 * Note the the internal subset (if present) is de-coupled
6501 * (i.e. not used), which could give problems if ID or IDREF
6502 * is present.
Owen Taylor3473f882001-02-23 17:55:21 +00006503 *
6504 * returns 1 if valid or 0 otherwise
6505 */
6506
6507int
6508xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6509 int ret;
William M. Brack367df6e2004-10-23 18:14:36 +00006510 xmlDtdPtr oldExt, oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006511 xmlNodePtr root;
6512
6513 if (dtd == NULL) return(0);
6514 if (doc == NULL) return(0);
6515 oldExt = doc->extSubset;
William M. Brack367df6e2004-10-23 18:14:36 +00006516 oldInt = doc->intSubset;
Owen Taylor3473f882001-02-23 17:55:21 +00006517 doc->extSubset = dtd;
William M. Brack367df6e2004-10-23 18:14:36 +00006518 doc->intSubset = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006519 ret = xmlValidateRoot(ctxt, doc);
6520 if (ret == 0) {
6521 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006522 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006523 return(ret);
6524 }
6525 if (doc->ids != NULL) {
6526 xmlFreeIDTable(doc->ids);
6527 doc->ids = NULL;
6528 }
6529 if (doc->refs != NULL) {
6530 xmlFreeRefTable(doc->refs);
6531 doc->refs = NULL;
6532 }
6533 root = xmlDocGetRootElement(doc);
6534 ret = xmlValidateElement(ctxt, doc, root);
6535 ret &= xmlValidateDocumentFinal(ctxt, doc);
6536 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006537 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006538 return(ret);
6539}
6540
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006541static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006542xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6543 const xmlChar *name ATTRIBUTE_UNUSED) {
6544 if (cur == NULL)
6545 return;
6546 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6547 xmlChar *notation = cur->content;
6548
Daniel Veillard878eab02002-02-19 13:46:09 +00006549 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006550 int ret;
6551
6552 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6553 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006554 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006555 }
6556 }
6557 }
6558}
6559
6560static void
Owen Taylor3473f882001-02-23 17:55:21 +00006561xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006562 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006563 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006564 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006565 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006566
Owen Taylor3473f882001-02-23 17:55:21 +00006567 if (cur == NULL)
6568 return;
6569 switch (cur->atype) {
6570 case XML_ATTRIBUTE_CDATA:
6571 case XML_ATTRIBUTE_ID:
6572 case XML_ATTRIBUTE_IDREF :
6573 case XML_ATTRIBUTE_IDREFS:
6574 case XML_ATTRIBUTE_NMTOKEN:
6575 case XML_ATTRIBUTE_NMTOKENS:
6576 case XML_ATTRIBUTE_ENUMERATION:
6577 break;
6578 case XML_ATTRIBUTE_ENTITY:
6579 case XML_ATTRIBUTE_ENTITIES:
6580 case XML_ATTRIBUTE_NOTATION:
6581 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006582
6583 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6584 cur->atype, cur->defaultValue);
6585 if ((ret == 0) && (ctxt->valid == 1))
6586 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006587 }
6588 if (cur->tree != NULL) {
6589 xmlEnumerationPtr tree = cur->tree;
6590 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006591 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006592 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006593 if ((ret == 0) && (ctxt->valid == 1))
6594 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006595 tree = tree->next;
6596 }
6597 }
6598 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006599 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6600 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006601 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006602 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006603 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006604 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006605 return;
6606 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006607
6608 if (doc != NULL)
6609 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6610 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006611 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006612 if ((elem == NULL) && (cur->parent != NULL) &&
6613 (cur->parent->type == XML_DTD_NODE))
6614 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006615 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006616 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006617 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006618 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006619 return;
6620 }
6621 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006622 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006623 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006624 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006625 ctxt->valid = 0;
6626 }
6627 }
Owen Taylor3473f882001-02-23 17:55:21 +00006628}
6629
6630/**
6631 * xmlValidateDtdFinal:
6632 * @ctxt: the validation context
6633 * @doc: a document instance
6634 *
6635 * Does the final step for the dtds validation once all the
6636 * subsets have been parsed
6637 *
6638 * basically it does the following checks described by the XML Rec
6639 * - check that ENTITY and ENTITIES type attributes default or
6640 * possible values matches one of the defined entities.
6641 * - check that NOTATION type attributes default or
6642 * possible values matches one of the defined notations.
6643 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006644 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006645 */
6646
6647int
6648xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006649 xmlDtdPtr dtd;
6650 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006651 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006652
6653 if (doc == NULL) return(0);
6654 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6655 return(0);
6656 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006657 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006658 dtd = doc->intSubset;
6659 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6660 table = (xmlAttributeTablePtr) dtd->attributes;
6661 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006662 }
6663 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006664 entities = (xmlEntitiesTablePtr) dtd->entities;
6665 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6666 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006667 }
6668 dtd = doc->extSubset;
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 return(ctxt->valid);
6679}
6680
6681/**
6682 * xmlValidateDocument:
6683 * @ctxt: the validation context
6684 * @doc: a document instance
6685 *
6686 * Try to validate the document instance
6687 *
6688 * basically it does the all the checks described by the XML Rec
6689 * i.e. validates the internal and external subset (if present)
6690 * and validate the document tree.
6691 *
6692 * returns 1 if valid or 0 otherwise
6693 */
6694
6695int
6696xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6697 int ret;
6698 xmlNodePtr root;
6699
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006700 if (doc == NULL)
6701 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006702 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006703 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6704 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006705 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006706 }
Owen Taylor3473f882001-02-23 17:55:21 +00006707 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6708 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
William M. Brack8c22f9f2004-08-06 16:23:27 +00006709 xmlChar *sysID;
6710 if (doc->intSubset->SystemID != NULL) {
William M. Brackbebe7302004-08-05 06:46:47 +00006711 sysID = xmlBuildURI(doc->intSubset->SystemID,
6712 doc->URL);
William M. Brack8c22f9f2004-08-06 16:23:27 +00006713 if (sysID == NULL) {
6714 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6715 "Could not build URI for external subset \"%s\"\n",
6716 (const char *) doc->intSubset->SystemID);
6717 return 0;
6718 }
6719 } else
William M. Brackbebe7302004-08-05 06:46:47 +00006720 sysID = NULL;
William M. Brack8c22f9f2004-08-06 16:23:27 +00006721 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
William M. Brackbebe7302004-08-05 06:46:47 +00006722 (const xmlChar *)sysID);
William M. Brackbebe7302004-08-05 06:46:47 +00006723 if (sysID != NULL)
6724 xmlFree(sysID);
Owen Taylor3473f882001-02-23 17:55:21 +00006725 if (doc->extSubset == NULL) {
6726 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006727 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006728 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006729 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006730 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006731 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006732 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006733 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006734 }
6735 return(0);
6736 }
6737 }
6738
6739 if (doc->ids != NULL) {
6740 xmlFreeIDTable(doc->ids);
6741 doc->ids = NULL;
6742 }
6743 if (doc->refs != NULL) {
6744 xmlFreeRefTable(doc->refs);
6745 doc->refs = NULL;
6746 }
6747 ret = xmlValidateDtdFinal(ctxt, doc);
6748 if (!xmlValidateRoot(ctxt, doc)) return(0);
6749
6750 root = xmlDocGetRootElement(doc);
6751 ret &= xmlValidateElement(ctxt, doc, root);
6752 ret &= xmlValidateDocumentFinal(ctxt, doc);
6753 return(ret);
6754}
6755
Owen Taylor3473f882001-02-23 17:55:21 +00006756/************************************************************************
6757 * *
6758 * Routines for dynamic validation editing *
6759 * *
6760 ************************************************************************/
6761
6762/**
6763 * xmlValidGetPotentialChildren:
6764 * @ctree: an element content tree
Daniel Veillard7802ba52005-10-27 11:56:20 +00006765 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006766 * @len: a pointer to the number of element in the list
6767 * @max: the size of the array
6768 *
6769 * Build/extend a list of potential children allowed by the content tree
6770 *
6771 * returns the number of element in the list, or -1 in case of error.
6772 */
6773
6774int
Daniel Veillard7802ba52005-10-27 11:56:20 +00006775xmlValidGetPotentialChildren(xmlElementContent *ctree,
6776 const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006777 int *len, int max) {
6778 int i;
6779
Daniel Veillard7802ba52005-10-27 11:56:20 +00006780 if ((ctree == NULL) || (names == NULL) || (len == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006781 return(-1);
6782 if (*len >= max) return(*len);
6783
6784 switch (ctree->type) {
6785 case XML_ELEMENT_CONTENT_PCDATA:
6786 for (i = 0; i < *len;i++)
Daniel Veillard7802ba52005-10-27 11:56:20 +00006787 if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
6788 names[(*len)++] = BAD_CAST "#PCDATA";
Owen Taylor3473f882001-02-23 17:55:21 +00006789 break;
6790 case XML_ELEMENT_CONTENT_ELEMENT:
6791 for (i = 0; i < *len;i++)
Daniel Veillard7802ba52005-10-27 11:56:20 +00006792 if (xmlStrEqual(ctree->name, names[i])) return(*len);
6793 names[(*len)++] = ctree->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006794 break;
6795 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard7802ba52005-10-27 11:56:20 +00006796 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6797 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
Owen Taylor3473f882001-02-23 17:55:21 +00006798 break;
6799 case XML_ELEMENT_CONTENT_OR:
Daniel Veillard7802ba52005-10-27 11:56:20 +00006800 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6801 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
Owen Taylor3473f882001-02-23 17:55:21 +00006802 break;
6803 }
6804
6805 return(*len);
6806}
6807
William M. Brack9333cc22004-06-24 08:33:40 +00006808/*
6809 * Dummy function to suppress messages while we try out valid elements
6810 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00006811static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
William M. Brack9333cc22004-06-24 08:33:40 +00006812 const char *msg ATTRIBUTE_UNUSED, ...) {
6813 return;
6814}
6815
Owen Taylor3473f882001-02-23 17:55:21 +00006816/**
6817 * xmlValidGetValidElements:
6818 * @prev: an element to insert after
6819 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006820 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006821 * @max: the size of the array
6822 *
6823 * This function returns the list of authorized children to insert
6824 * within an existing tree while respecting the validity constraints
6825 * forced by the Dtd. The insertion point is defined using @prev and
6826 * @next in the following ways:
6827 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6828 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6829 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6830 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6831 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6832 *
6833 * pointers to the element names are inserted at the beginning of the array
6834 * and do not need to be freed.
6835 *
6836 * returns the number of element in the list, or -1 in case of error. If
6837 * the function returns the value @max the caller is invited to grow the
6838 * receiving array and retry.
6839 */
6840
6841int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006842xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006843 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006844 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006845 int nb_valid_elements = 0;
6846 const xmlChar *elements[256];
6847 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006848 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006849
6850 xmlNode *ref_node;
6851 xmlNode *parent;
6852 xmlNode *test_node;
6853
6854 xmlNode *prev_next;
6855 xmlNode *next_prev;
6856 xmlNode *parent_childs;
6857 xmlNode *parent_last;
6858
6859 xmlElement *element_desc;
6860
6861 if (prev == NULL && next == NULL)
6862 return(-1);
6863
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006864 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006865 if (max <= 0) return(-1);
6866
William M. Brack9333cc22004-06-24 08:33:40 +00006867 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6868 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6869
Owen Taylor3473f882001-02-23 17:55:21 +00006870 nb_valid_elements = 0;
6871 ref_node = prev ? prev : next;
6872 parent = ref_node->parent;
6873
6874 /*
6875 * Retrieves the parent element declaration
6876 */
6877 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6878 parent->name);
6879 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6880 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6881 parent->name);
6882 if (element_desc == NULL) return(-1);
6883
6884 /*
6885 * Do a backup of the current tree structure
6886 */
6887 prev_next = prev ? prev->next : NULL;
6888 next_prev = next ? next->prev : NULL;
6889 parent_childs = parent->children;
6890 parent_last = parent->last;
6891
6892 /*
6893 * Creates a dummy node and insert it into the tree
6894 */
Daniel Veillard95ddcd32004-10-26 21:53:55 +00006895 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006896 test_node->parent = parent;
6897 test_node->prev = prev;
6898 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006899 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006900
6901 if (prev) prev->next = test_node;
6902 else parent->children = test_node;
6903
6904 if (next) next->prev = test_node;
6905 else parent->last = test_node;
6906
6907 /*
6908 * Insert each potential child node and check if the parent is
6909 * still valid
6910 */
6911 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6912 elements, &nb_elements, 256);
6913
6914 for (i = 0;i < nb_elements;i++) {
6915 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006916 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006917 int j;
6918
6919 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006920 if (xmlStrEqual(elements[i], names[j])) break;
6921 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00006922 if (nb_valid_elements >= max) break;
6923 }
6924 }
6925
6926 /*
6927 * Restore the tree structure
6928 */
6929 if (prev) prev->next = prev_next;
6930 if (next) next->prev = next_prev;
6931 parent->children = parent_childs;
6932 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006933
6934 /*
6935 * Free up the dummy node
6936 */
6937 test_node->name = name;
6938 xmlFreeNode(test_node);
6939
Owen Taylor3473f882001-02-23 17:55:21 +00006940 return(nb_valid_elements);
6941}
Daniel Veillard4432df22003-09-28 18:58:27 +00006942#endif /* LIBXML_VALID_ENABLED */
6943
Daniel Veillard5d4644e2005-04-01 13:11:58 +00006944#define bottom_valid
6945#include "elfgcchack.h"