blob: ea47142c88fbbc4f0e7426da46ad797e47d4949d [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 Veillardae0765b2008-07-31 19:54:59 +000039#ifdef LIBXML_VALID_ENABLED
40static int
41xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
42 const xmlChar *value);
43#endif
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000044/************************************************************************
45 * *
46 * Error handling routines *
47 * *
48 ************************************************************************/
49
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000050/**
Daniel Veillardce9457f2003-10-05 21:33:18 +000051 * xmlVErrMemory:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000052 * @ctxt: an XML validation parser context
53 * @extra: extra informations
54 *
55 * Handle an out of memory error
56 */
57static void
Daniel Veillardce9457f2003-10-05 21:33:18 +000058xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000059{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000060 xmlGenericErrorFunc channel = NULL;
61 xmlParserCtxtPtr pctxt = NULL;
62 void *data = NULL;
63
64 if (ctxt != NULL) {
65 channel = ctxt->error;
66 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +000067 /* Use the special values to detect if it is part of a parsing
68 context */
69 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
70 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +000071 long delta = (char *) ctxt - (char *) ctxt->userData;
72 if ((delta > 0) && (delta < 250))
73 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +000074 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +000075 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000076 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000077 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000078 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000079 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
80 "Memory allocation failed : %s\n", extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000081 else
Daniel Veillard73000572003-10-11 11:26:42 +000082 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000083 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000084 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
85 "Memory allocation failed\n");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000086}
87
88/**
89 * xmlErrValid:
90 * @ctxt: an XML validation parser context
Daniel Veillardbb5abab2003-10-03 22:21:51 +000091 * @error: the error number
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000092 * @extra: extra informations
93 *
94 * Handle a validation error
95 */
96static void
Daniel Veillardf88d8cf2003-12-08 10:25:02 +000097xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000098 const char *msg, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000099{
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000100 xmlGenericErrorFunc channel = NULL;
101 xmlParserCtxtPtr pctxt = NULL;
102 void *data = NULL;
103
104 if (ctxt != NULL) {
105 channel = ctxt->error;
106 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000107 /* Use the special values to detect if it is part of a parsing
108 context */
109 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
110 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +0000111 long delta = (char *) ctxt - (char *) ctxt->userData;
112 if ((delta > 0) && (delta < 250))
113 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000114 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000115 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000116 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +0000117 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000118 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000119 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
120 msg, extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000121 else
Daniel Veillard73000572003-10-11 11:26:42 +0000122 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000123 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000124 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200125 "%s", msg);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000126}
127
Daniel Veillardf54cd532004-02-25 11:52:31 +0000128#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
129/**
130 * xmlErrValidNode:
131 * @ctxt: an XML validation parser context
132 * @node: the node raising the error
133 * @error: the error number
134 * @str1: extra informations
135 * @str2: extra informations
136 * @str3: extra informations
137 *
138 * Handle a validation error, provide contextual informations
139 */
140static void
141xmlErrValidNode(xmlValidCtxtPtr ctxt,
142 xmlNodePtr node, xmlParserErrors error,
143 const char *msg, const xmlChar * str1,
144 const xmlChar * str2, const xmlChar * str3)
145{
146 xmlStructuredErrorFunc schannel = NULL;
147 xmlGenericErrorFunc channel = NULL;
148 xmlParserCtxtPtr pctxt = NULL;
149 void *data = NULL;
150
151 if (ctxt != NULL) {
152 channel = ctxt->error;
153 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000154 /* Use the special values to detect if it is part of a parsing
155 context */
156 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
157 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +0000158 long delta = (char *) ctxt - (char *) ctxt->userData;
159 if ((delta > 0) && (delta < 250))
160 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000161 }
Daniel Veillardf54cd532004-02-25 11:52:31 +0000162 }
163 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
164 XML_ERR_ERROR, NULL, 0,
165 (const char *) str1,
166 (const char *) str1,
167 (const char *) str3, 0, 0, msg, str1, str2, str3);
168}
169#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
170
Daniel Veillardd61e8fb2003-10-19 21:59:17 +0000171#ifdef LIBXML_VALID_ENABLED
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000172/**
173 * xmlErrValidNodeNr:
174 * @ctxt: an XML validation parser context
175 * @node: the node raising the error
176 * @error: the error number
177 * @str1: extra informations
178 * @int2: extra informations
179 * @str3: extra informations
180 *
181 * Handle a validation error, provide contextual informations
182 */
183static void
Daniel Veillard72b9e292003-10-28 15:44:17 +0000184xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000185 xmlNodePtr node, xmlParserErrors error,
186 const char *msg, const xmlChar * str1,
187 int int2, const xmlChar * str3)
188{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000189 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000190 xmlGenericErrorFunc channel = NULL;
191 xmlParserCtxtPtr pctxt = NULL;
192 void *data = NULL;
193
194 if (ctxt != NULL) {
195 channel = ctxt->error;
196 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000197 /* Use the special values to detect if it is part of a parsing
198 context */
199 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
200 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +0000201 long delta = (char *) ctxt - (char *) ctxt->userData;
202 if ((delta > 0) && (delta < 250))
203 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000204 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000205 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000206 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000207 XML_ERR_ERROR, NULL, 0,
208 (const char *) str1,
209 (const char *) str3,
210 NULL, int2, 0, msg, str1, int2, str3);
211}
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000212
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000213/**
214 * xmlErrValidWarning:
215 * @ctxt: an XML validation parser context
216 * @node: the node raising the error
217 * @error: the error number
William M. Brackedb65a72004-02-06 07:36:04 +0000218 * @str1: extra information
219 * @str2: extra information
220 * @str3: extra information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000221 *
William M. Brackedb65a72004-02-06 07:36:04 +0000222 * Handle a validation error, provide contextual information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000223 */
224static void
William M. Brackedb65a72004-02-06 07:36:04 +0000225xmlErrValidWarning(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000226 xmlNodePtr node, xmlParserErrors error,
227 const char *msg, const xmlChar * str1,
228 const xmlChar * str2, const xmlChar * str3)
229{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000230 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000231 xmlGenericErrorFunc channel = NULL;
232 xmlParserCtxtPtr pctxt = NULL;
233 void *data = NULL;
234
235 if (ctxt != NULL) {
William M. Bracke4d526f2004-12-18 00:01:21 +0000236 channel = ctxt->warning;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000237 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000238 /* Use the special values to detect if it is part of a parsing
239 context */
240 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
241 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +0000242 long delta = (char *) ctxt - (char *) ctxt->userData;
243 if ((delta > 0) && (delta < 250))
244 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000245 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000246 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000247 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000248 XML_ERR_WARNING, NULL, 0,
249 (const char *) str1,
250 (const char *) str1,
251 (const char *) str3, 0, 0, msg, str1, str2, str3);
252}
253
254
Daniel Veillardea7751d2002-12-20 00:16:24 +0000255
256#ifdef LIBXML_REGEXP_ENABLED
257/*
258 * If regexp are enabled we can do continuous validation without the
259 * need of a tree to validate the content model. this is done in each
260 * callbacks.
261 * Each xmlValidState represent the validation state associated to the
262 * set of nodes currently open from the document root to the current element.
263 */
264
265
266typedef struct _xmlValidState {
267 xmlElementPtr elemDecl; /* pointer to the content model */
268 xmlNodePtr node; /* pointer to the current node */
269 xmlRegExecCtxtPtr exec; /* regexp runtime */
270} _xmlValidState;
271
272
273static int
274vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000275 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000276 ctxt->vstateMax = 10;
277 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
278 sizeof(ctxt->vstateTab[0]));
279 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000280 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000281 return(-1);
282 }
283 }
284
285 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000286 xmlValidState *tmp;
287
288 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
289 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
290 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000291 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000292 return(-1);
293 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000294 ctxt->vstateMax *= 2;
295 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000296 }
297 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
298 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
299 ctxt->vstateTab[ctxt->vstateNr].node = node;
300 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
301 if (elemDecl->contModel == NULL)
302 xmlValidBuildContentModel(ctxt, elemDecl);
303 if (elemDecl->contModel != NULL) {
304 ctxt->vstateTab[ctxt->vstateNr].exec =
305 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
306 } else {
307 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000308 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
309 XML_ERR_INTERNAL_ERROR,
310 "Failed to build content model regexp for %s\n",
311 node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000312 }
313 }
314 return(ctxt->vstateNr++);
315}
316
317static int
318vstateVPop(xmlValidCtxtPtr ctxt) {
319 xmlElementPtr elemDecl;
320
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000321 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000322 ctxt->vstateNr--;
323 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
324 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
325 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
326 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
327 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
328 }
329 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
330 if (ctxt->vstateNr >= 1)
331 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
332 else
333 ctxt->vstate = NULL;
334 return(ctxt->vstateNr);
335}
336
337#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000338/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000339 * If regexp are not enabled, it uses a home made algorithm less
340 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000341 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000342 * only restriction is on the deepness of the tree limited by the
343 * size of the occurs bitfield
344 *
345 * this is the content of a saved state for rollbacks
346 */
347
348#define ROLLBACK_OR 0
349#define ROLLBACK_PARENT 1
350
Daniel Veillardb44025c2001-10-11 22:55:55 +0000351typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000352 xmlElementContentPtr cont; /* pointer to the content model subtree */
353 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000354 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000355 unsigned char depth; /* current depth in the overall tree */
356 unsigned char state; /* ROLLBACK_XXX */
357} _xmlValidState;
358
Daniel Veillardfc57b412002-04-29 15:50:14 +0000359#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000360#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
361#define CONT ctxt->vstate->cont
362#define NODE ctxt->vstate->node
363#define DEPTH ctxt->vstate->depth
364#define OCCURS ctxt->vstate->occurs
365#define STATE ctxt->vstate->state
366
Daniel Veillard5344c602001-12-31 16:37:34 +0000367#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
368#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000369
Daniel Veillard5344c602001-12-31 16:37:34 +0000370#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
371#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000372
373static int
374vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
375 xmlNodePtr node, unsigned char depth, long occurs,
376 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000377 int i = ctxt->vstateNr - 1;
378
Daniel Veillard940492d2002-04-15 10:15:25 +0000379 if (ctxt->vstateNr > MAX_RECURSE) {
380 return(-1);
381 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000382 if (ctxt->vstateTab == NULL) {
383 ctxt->vstateMax = 8;
384 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
385 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
386 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000387 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000388 return(-1);
389 }
390 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000391 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000392 xmlValidState *tmp;
393
394 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
395 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
396 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000397 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000398 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000399 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000400 ctxt->vstateMax *= 2;
401 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000402 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000403 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000404 /*
405 * Don't push on the stack a state already here
406 */
407 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
408 (ctxt->vstateTab[i].node == node) &&
409 (ctxt->vstateTab[i].depth == depth) &&
410 (ctxt->vstateTab[i].occurs == occurs) &&
411 (ctxt->vstateTab[i].state == state))
412 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000413 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
414 ctxt->vstateTab[ctxt->vstateNr].node = node;
415 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
416 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
417 ctxt->vstateTab[ctxt->vstateNr].state = state;
418 return(ctxt->vstateNr++);
419}
420
421static int
422vstateVPop(xmlValidCtxtPtr ctxt) {
423 if (ctxt->vstateNr <= 1) return(-1);
424 ctxt->vstateNr--;
425 ctxt->vstate = &ctxt->vstateTab[0];
426 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
427 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
428 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
429 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
430 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
431 return(ctxt->vstateNr);
432}
433
Daniel Veillard118aed72002-09-24 14:13:13 +0000434#endif /* LIBXML_REGEXP_ENABLED */
435
Daniel Veillard1c732d22002-11-30 11:22:59 +0000436static int
437nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
438{
439 if (ctxt->nodeMax <= 0) {
440 ctxt->nodeMax = 4;
441 ctxt->nodeTab =
442 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
443 sizeof(ctxt->nodeTab[0]));
444 if (ctxt->nodeTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000445 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000446 ctxt->nodeMax = 0;
447 return (0);
448 }
449 }
450 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000451 xmlNodePtr *tmp;
452 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
453 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
454 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000455 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000456 return (0);
457 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000458 ctxt->nodeMax *= 2;
459 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000460 }
461 ctxt->nodeTab[ctxt->nodeNr] = value;
462 ctxt->node = value;
463 return (ctxt->nodeNr++);
464}
465static xmlNodePtr
466nodeVPop(xmlValidCtxtPtr ctxt)
467{
468 xmlNodePtr ret;
469
470 if (ctxt->nodeNr <= 0)
Daniel Veillard24505b02005-07-28 23:49:35 +0000471 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +0000472 ctxt->nodeNr--;
473 if (ctxt->nodeNr > 0)
474 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
475 else
476 ctxt->node = NULL;
477 ret = ctxt->nodeTab[ctxt->nodeNr];
Daniel Veillard24505b02005-07-28 23:49:35 +0000478 ctxt->nodeTab[ctxt->nodeNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000479 return (ret);
480}
Owen Taylor3473f882001-02-23 17:55:21 +0000481
Owen Taylor3473f882001-02-23 17:55:21 +0000482#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000483static void
484xmlValidPrintNode(xmlNodePtr cur) {
485 if (cur == NULL) {
486 xmlGenericError(xmlGenericErrorContext, "null");
487 return;
488 }
489 switch (cur->type) {
490 case XML_ELEMENT_NODE:
491 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
492 break;
493 case XML_TEXT_NODE:
494 xmlGenericError(xmlGenericErrorContext, "text ");
495 break;
496 case XML_CDATA_SECTION_NODE:
497 xmlGenericError(xmlGenericErrorContext, "cdata ");
498 break;
499 case XML_ENTITY_REF_NODE:
500 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
501 break;
502 case XML_PI_NODE:
503 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
504 break;
505 case XML_COMMENT_NODE:
506 xmlGenericError(xmlGenericErrorContext, "comment ");
507 break;
508 case XML_ATTRIBUTE_NODE:
509 xmlGenericError(xmlGenericErrorContext, "?attr? ");
510 break;
511 case XML_ENTITY_NODE:
512 xmlGenericError(xmlGenericErrorContext, "?ent? ");
513 break;
514 case XML_DOCUMENT_NODE:
515 xmlGenericError(xmlGenericErrorContext, "?doc? ");
516 break;
517 case XML_DOCUMENT_TYPE_NODE:
518 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
519 break;
520 case XML_DOCUMENT_FRAG_NODE:
521 xmlGenericError(xmlGenericErrorContext, "?frag? ");
522 break;
523 case XML_NOTATION_NODE:
524 xmlGenericError(xmlGenericErrorContext, "?nota? ");
525 break;
526 case XML_HTML_DOCUMENT_NODE:
527 xmlGenericError(xmlGenericErrorContext, "?html? ");
528 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000529#ifdef LIBXML_DOCB_ENABLED
530 case XML_DOCB_DOCUMENT_NODE:
531 xmlGenericError(xmlGenericErrorContext, "?docb? ");
532 break;
533#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000534 case XML_DTD_NODE:
535 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
536 break;
537 case XML_ELEMENT_DECL:
538 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
539 break;
540 case XML_ATTRIBUTE_DECL:
541 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
542 break;
543 case XML_ENTITY_DECL:
544 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
545 break;
546 case XML_NAMESPACE_DECL:
547 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
548 break;
549 case XML_XINCLUDE_START:
550 xmlGenericError(xmlGenericErrorContext, "incstart ");
551 break;
552 case XML_XINCLUDE_END:
553 xmlGenericError(xmlGenericErrorContext, "incend ");
554 break;
555 }
556}
557
558static void
559xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000560 if (cur == NULL)
561 xmlGenericError(xmlGenericErrorContext, "null ");
562 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000563 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000564 cur = cur->next;
565 }
566}
567
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000568static void
569xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000570 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000571
572 expr[0] = 0;
573 xmlGenericError(xmlGenericErrorContext, "valid: ");
574 xmlValidPrintNodeList(cur);
575 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000576 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000577 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
578}
579
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000580static void
581xmlValidDebugState(xmlValidStatePtr state) {
582 xmlGenericError(xmlGenericErrorContext, "(");
583 if (state->cont == NULL)
584 xmlGenericError(xmlGenericErrorContext, "null,");
585 else
586 switch (state->cont->type) {
587 case XML_ELEMENT_CONTENT_PCDATA:
588 xmlGenericError(xmlGenericErrorContext, "pcdata,");
589 break;
590 case XML_ELEMENT_CONTENT_ELEMENT:
591 xmlGenericError(xmlGenericErrorContext, "%s,",
592 state->cont->name);
593 break;
594 case XML_ELEMENT_CONTENT_SEQ:
595 xmlGenericError(xmlGenericErrorContext, "seq,");
596 break;
597 case XML_ELEMENT_CONTENT_OR:
598 xmlGenericError(xmlGenericErrorContext, "or,");
599 break;
600 }
601 xmlValidPrintNode(state->node);
602 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
603 state->depth, state->occurs, state->state);
604}
605
606static void
607xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
608 int i, j;
609
610 xmlGenericError(xmlGenericErrorContext, "state: ");
611 xmlValidDebugState(ctxt->vstate);
612 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
613 ctxt->vstateNr - 1);
614 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
615 xmlValidDebugState(&ctxt->vstateTab[j]);
616 xmlGenericError(xmlGenericErrorContext, "\n");
617}
618
619/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000620#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000621 *****/
622
623#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000624#define DEBUG_VALID_MSG(m) \
625 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
626
Owen Taylor3473f882001-02-23 17:55:21 +0000627#else
628#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000629#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000630#endif
631
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000632/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000633
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000634
Owen Taylor3473f882001-02-23 17:55:21 +0000635#define CHECK_DTD \
636 if (doc == NULL) return(0); \
637 else if ((doc->intSubset == NULL) && \
638 (doc->extSubset == NULL)) return(0)
639
Owen Taylor3473f882001-02-23 17:55:21 +0000640xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
641
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000642#ifdef LIBXML_REGEXP_ENABLED
643
644/************************************************************************
645 * *
646 * Content model validation based on the regexps *
647 * *
648 ************************************************************************/
649
650/**
651 * xmlValidBuildAContentModel:
652 * @content: the content model
653 * @ctxt: the schema parser context
654 * @name: the element name whose content is being built
655 *
656 * Generate the automata sequence needed for that type
657 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000658 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000659 */
660static int
661xmlValidBuildAContentModel(xmlElementContentPtr content,
662 xmlValidCtxtPtr ctxt,
663 const xmlChar *name) {
664 if (content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000665 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
666 "Found NULL content in content model of %s\n",
667 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000668 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000669 }
670 switch (content->type) {
671 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000672 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
673 "Found PCDATA in content model of %s\n",
674 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000675 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000676 break;
677 case XML_ELEMENT_CONTENT_ELEMENT: {
678 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000679 xmlChar fn[50];
680 xmlChar *fullname;
681
682 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
683 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000684 xmlVErrMemory(ctxt, "Building content model");
Daniel Veillardc00cda82003-04-07 10:22:39 +0000685 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000686 }
687
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000688 switch (content->ocur) {
689 case XML_ELEMENT_CONTENT_ONCE:
690 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000691 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000692 break;
693 case XML_ELEMENT_CONTENT_OPT:
694 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000695 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000696 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
697 break;
698 case XML_ELEMENT_CONTENT_PLUS:
699 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000700 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000701 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000702 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000703 break;
704 case XML_ELEMENT_CONTENT_MULT:
William M. Brack8b0cbb02004-04-17 13:31:06 +0000705 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
706 ctxt->state, NULL);
707 xmlAutomataNewTransition(ctxt->am,
708 ctxt->state, ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000709 break;
710 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000711 if ((fullname != fn) && (fullname != content->name))
712 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000713 break;
714 }
715 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000716 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000717 xmlElementContentOccur ocur;
718
719 /*
720 * Simply iterate over the content
721 */
722 oldstate = ctxt->state;
723 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000724 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
725 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
726 oldstate = ctxt->state;
727 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000728 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000729 xmlValidBuildAContentModel(content->c1, ctxt, name);
730 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000731 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
732 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
733 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000734 oldend = ctxt->state;
735 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000736 switch (ocur) {
737 case XML_ELEMENT_CONTENT_ONCE:
738 break;
739 case XML_ELEMENT_CONTENT_OPT:
740 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
741 break;
742 case XML_ELEMENT_CONTENT_MULT:
743 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000744 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000745 break;
746 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000747 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000748 break;
749 }
750 break;
751 }
752 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000753 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000754 xmlElementContentOccur ocur;
755
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000756 ocur = content->ocur;
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000757 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
758 (ocur == XML_ELEMENT_CONTENT_MULT)) {
759 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
760 ctxt->state, NULL);
761 }
762 oldstate = ctxt->state;
763 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000764
765 /*
766 * iterate over the subtypes and remerge the end with an
767 * epsilon transition
768 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000769 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000770 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000771 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000772 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000773 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000774 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
775 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000776 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000777 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000778 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
779 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000780 switch (ocur) {
781 case XML_ELEMENT_CONTENT_ONCE:
782 break;
783 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000784 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000785 break;
786 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000787 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
788 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000789 break;
790 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000791 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000792 break;
793 }
794 break;
795 }
796 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000797 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
798 "ContentModel broken for element %s\n",
799 (const char *) name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000800 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000801 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000802 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000803}
804/**
805 * xmlValidBuildContentModel:
806 * @ctxt: a validation context
807 * @elem: an element declaration node
808 *
809 * (Re)Build the automata associated to the content model of this
810 * element
811 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000812 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000813 */
814int
815xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000816
817 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000818 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000819 if (elem->type != XML_ELEMENT_DECL)
820 return(0);
821 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
822 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000823 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000824 if (elem->contModel != NULL) {
825 if (!xmlRegexpIsDeterminist(elem->contModel)) {
826 ctxt->valid = 0;
827 return(0);
828 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000829 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000830 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000831
832 ctxt->am = xmlNewAutomata();
833 if (ctxt->am == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000834 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
835 XML_ERR_INTERNAL_ERROR,
836 "Cannot create automata for element %s\n",
837 elem->name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000838 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000839 }
William M. Brack78637da2003-07-31 14:47:38 +0000840 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000841 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
842 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000843 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000844 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000845 char expr[5000];
846 expr[0] = 0;
847 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000848 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
849 XML_DTD_CONTENT_NOT_DETERMINIST,
850 "Content model of %s is not determinist: %s\n",
851 elem->name, BAD_CAST expr, NULL);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000852#ifdef DEBUG_REGEXP_ALGO
853 xmlRegexpPrint(stderr, elem->contModel);
854#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000855 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000856 ctxt->state = NULL;
857 xmlFreeAutomata(ctxt->am);
858 ctxt->am = NULL;
859 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000860 }
861 ctxt->state = NULL;
862 xmlFreeAutomata(ctxt->am);
863 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000864 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000865}
866
867#endif /* LIBXML_REGEXP_ENABLED */
868
Owen Taylor3473f882001-02-23 17:55:21 +0000869/****************************************************************
870 * *
871 * Util functions for data allocation/deallocation *
872 * *
873 ****************************************************************/
874
875/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000876 * xmlNewValidCtxt:
877 *
878 * Allocate a validation context structure.
879 *
880 * Returns NULL if not, otherwise the new validation context structure
881 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000882xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000883 xmlValidCtxtPtr ret;
884
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000885 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000886 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000887 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000888 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000889
890 (void) memset(ret, 0, sizeof (xmlValidCtxt));
891
892 return (ret);
893}
894
895/**
896 * xmlFreeValidCtxt:
897 * @cur: the validation context to free
898 *
899 * Free a validation context structure.
900 */
901void
902xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
Daniel Veillardc0be74b2004-11-03 19:16:55 +0000903 if (cur->vstateTab != NULL)
904 xmlFree(cur->vstateTab);
905 if (cur->nodeTab != NULL)
906 xmlFree(cur->nodeTab);
Daniel Veillarda37aab82003-06-09 09:10:36 +0000907 xmlFree(cur);
908}
909
Daniel Veillard4432df22003-09-28 18:58:27 +0000910#endif /* LIBXML_VALID_ENABLED */
911
Daniel Veillarda37aab82003-06-09 09:10:36 +0000912/**
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000913 * xmlNewDocElementContent:
914 * @doc: the document
Owen Taylor3473f882001-02-23 17:55:21 +0000915 * @name: the subelement name or NULL
916 * @type: the type of element content decl
917 *
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000918 * Allocate an element content structure for the document.
Owen Taylor3473f882001-02-23 17:55:21 +0000919 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000920 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000921 */
922xmlElementContentPtr
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000923xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
924 xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000925 xmlElementContentPtr ret;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000926 xmlDictPtr dict = NULL;
927
928 if (doc != NULL)
929 dict = doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +0000930
931 switch(type) {
932 case XML_ELEMENT_CONTENT_ELEMENT:
933 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000934 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
935 "xmlNewElementContent : name == NULL !\n",
936 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000937 }
938 break;
939 case XML_ELEMENT_CONTENT_PCDATA:
940 case XML_ELEMENT_CONTENT_SEQ:
941 case XML_ELEMENT_CONTENT_OR:
942 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000943 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
944 "xmlNewElementContent : name != NULL !\n",
945 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000946 }
947 break;
948 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000949 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
950 "Internal: ELEMENT content corrupted invalid type\n",
951 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000952 return(NULL);
953 }
954 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
955 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000956 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000957 return(NULL);
958 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000959 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000960 ret->type = type;
961 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000962 if (name != NULL) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000963 int l;
964 const xmlChar *tmp;
965
966 tmp = xmlSplitQName3(name, &l);
967 if (tmp == NULL) {
968 if (dict == NULL)
969 ret->name = xmlStrdup(name);
970 else
971 ret->name = xmlDictLookup(dict, name, -1);
972 } else {
973 if (dict == NULL) {
974 ret->prefix = xmlStrndup(name, l);
975 ret->name = xmlStrdup(tmp);
976 } else {
977 ret->prefix = xmlDictLookup(dict, name, l);
978 ret->name = xmlDictLookup(dict, tmp, -1);
979 }
980 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000981 }
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000982 return(ret);
983}
984
985/**
986 * xmlNewElementContent:
987 * @name: the subelement name or NULL
988 * @type: the type of element content decl
989 *
990 * Allocate an element content structure.
991 * Deprecated in favor of xmlNewDocElementContent
992 *
993 * Returns NULL if not, otherwise the new element content structure
994 */
995xmlElementContentPtr
996xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
997 return(xmlNewDocElementContent(NULL, name, type));
998}
999
1000/**
1001 * xmlCopyDocElementContent:
1002 * @doc: the document owning the element declaration
1003 * @cur: An element content pointer.
1004 *
1005 * Build a copy of an element content description.
1006 *
1007 * Returns the new xmlElementContentPtr or NULL in case of error.
1008 */
1009xmlElementContentPtr
1010xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1011 xmlElementContentPtr ret = NULL, prev = NULL, tmp;
1012 xmlDictPtr dict = NULL;
1013
1014 if (cur == NULL) return(NULL);
1015
1016 if (doc != NULL)
1017 dict = doc->dict;
1018
1019 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1020 if (ret == NULL) {
1021 xmlVErrMemory(NULL, "malloc failed");
1022 return(NULL);
1023 }
1024 memset(ret, 0, sizeof(xmlElementContent));
1025 ret->type = cur->type;
1026 ret->ocur = cur->ocur;
1027 if (cur->name != NULL) {
1028 if (dict)
1029 ret->name = xmlDictLookup(dict, cur->name, -1);
1030 else
1031 ret->name = xmlStrdup(cur->name);
1032 }
1033
1034 if (cur->prefix != NULL) {
1035 if (dict)
1036 ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1037 else
1038 ret->prefix = xmlStrdup(cur->prefix);
1039 }
1040 if (cur->c1 != NULL)
1041 ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1042 if (ret->c1 != NULL)
1043 ret->c1->parent = ret;
1044 if (cur->c2 != NULL) {
1045 prev = ret;
1046 cur = cur->c2;
1047 while (cur != NULL) {
1048 tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1049 if (tmp == NULL) {
1050 xmlVErrMemory(NULL, "malloc failed");
1051 return(ret);
1052 }
1053 memset(tmp, 0, sizeof(xmlElementContent));
1054 tmp->type = cur->type;
1055 tmp->ocur = cur->ocur;
1056 prev->c2 = tmp;
1057 if (cur->name != NULL) {
1058 if (dict)
1059 tmp->name = xmlDictLookup(dict, cur->name, -1);
1060 else
1061 tmp->name = xmlStrdup(cur->name);
1062 }
1063
1064 if (cur->prefix != NULL) {
1065 if (dict)
1066 tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1067 else
1068 tmp->prefix = xmlStrdup(cur->prefix);
1069 }
1070 if (cur->c1 != NULL)
1071 tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1072 if (tmp->c1 != NULL)
1073 tmp->c1->parent = ret;
1074 prev = tmp;
1075 cur = cur->c2;
1076 }
1077 }
Owen Taylor3473f882001-02-23 17:55:21 +00001078 return(ret);
1079}
1080
1081/**
1082 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +00001083 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +00001084 *
1085 * Build a copy of an element content description.
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001086 * Deprecated, use xmlCopyDocElementContent instead
Owen Taylor3473f882001-02-23 17:55:21 +00001087 *
1088 * Returns the new xmlElementContentPtr or NULL in case of error.
1089 */
1090xmlElementContentPtr
1091xmlCopyElementContent(xmlElementContentPtr cur) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001092 return(xmlCopyDocElementContent(NULL, cur));
1093}
Owen Taylor3473f882001-02-23 17:55:21 +00001094
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001095/**
1096 * xmlFreeDocElementContent:
1097 * @doc: the document owning the element declaration
1098 * @cur: the element content tree to free
1099 *
1100 * Free an element content structure. The whole subtree is removed.
1101 */
1102void
1103xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1104 xmlElementContentPtr next;
1105 xmlDictPtr dict = NULL;
1106
1107 if (doc != NULL)
1108 dict = doc->dict;
1109
1110 while (cur != NULL) {
1111 next = cur->c2;
1112 switch (cur->type) {
1113 case XML_ELEMENT_CONTENT_PCDATA:
1114 case XML_ELEMENT_CONTENT_ELEMENT:
1115 case XML_ELEMENT_CONTENT_SEQ:
1116 case XML_ELEMENT_CONTENT_OR:
1117 break;
1118 default:
1119 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1120 "Internal: ELEMENT content corrupted invalid type\n",
1121 NULL);
1122 return;
1123 }
1124 if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1);
1125 if (dict) {
1126 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1127 xmlFree((xmlChar *) cur->name);
1128 if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1129 xmlFree((xmlChar *) cur->prefix);
1130 } else {
1131 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1132 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1133 }
1134 xmlFree(cur);
1135 cur = next;
Owen Taylor3473f882001-02-23 17:55:21 +00001136 }
Owen Taylor3473f882001-02-23 17:55:21 +00001137}
1138
1139/**
1140 * xmlFreeElementContent:
1141 * @cur: the element content tree to free
1142 *
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001143 * Free an element content structure. The whole subtree is removed.
1144 * Deprecated, use xmlFreeDocElementContent instead
Owen Taylor3473f882001-02-23 17:55:21 +00001145 */
1146void
1147xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001148 xmlFreeDocElementContent(NULL, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001149}
1150
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001151#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001152/**
1153 * xmlDumpElementContent:
1154 * @buf: An XML buffer
1155 * @content: An element table
1156 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1157 *
1158 * This will dump the content of the element table as an XML DTD definition
1159 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001160static void
Owen Taylor3473f882001-02-23 17:55:21 +00001161xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1162 if (content == NULL) return;
1163
1164 if (glob) xmlBufferWriteChar(buf, "(");
1165 switch (content->type) {
1166 case XML_ELEMENT_CONTENT_PCDATA:
1167 xmlBufferWriteChar(buf, "#PCDATA");
1168 break;
1169 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001170 if (content->prefix != NULL) {
1171 xmlBufferWriteCHAR(buf, content->prefix);
1172 xmlBufferWriteChar(buf, ":");
1173 }
Owen Taylor3473f882001-02-23 17:55:21 +00001174 xmlBufferWriteCHAR(buf, content->name);
1175 break;
1176 case XML_ELEMENT_CONTENT_SEQ:
1177 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1178 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1179 xmlDumpElementContent(buf, content->c1, 1);
1180 else
1181 xmlDumpElementContent(buf, content->c1, 0);
1182 xmlBufferWriteChar(buf, " , ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001183 if ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1184 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
1185 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001186 xmlDumpElementContent(buf, content->c2, 1);
1187 else
1188 xmlDumpElementContent(buf, content->c2, 0);
1189 break;
1190 case XML_ELEMENT_CONTENT_OR:
1191 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1192 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1193 xmlDumpElementContent(buf, content->c1, 1);
1194 else
1195 xmlDumpElementContent(buf, content->c1, 0);
1196 xmlBufferWriteChar(buf, " | ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001197 if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1198 ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
1199 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001200 xmlDumpElementContent(buf, content->c2, 1);
1201 else
1202 xmlDumpElementContent(buf, content->c2, 0);
1203 break;
1204 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001205 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1206 "Internal: ELEMENT content corrupted invalid type\n",
1207 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001208 }
1209 if (glob)
1210 xmlBufferWriteChar(buf, ")");
1211 switch (content->ocur) {
1212 case XML_ELEMENT_CONTENT_ONCE:
1213 break;
1214 case XML_ELEMENT_CONTENT_OPT:
1215 xmlBufferWriteChar(buf, "?");
1216 break;
1217 case XML_ELEMENT_CONTENT_MULT:
1218 xmlBufferWriteChar(buf, "*");
1219 break;
1220 case XML_ELEMENT_CONTENT_PLUS:
1221 xmlBufferWriteChar(buf, "+");
1222 break;
1223 }
1224}
1225
1226/**
1227 * xmlSprintfElementContent:
1228 * @buf: an output buffer
1229 * @content: An element table
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001230 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001231 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001232 * Deprecated, unsafe, use xmlSnprintfElementContent
1233 */
1234void
1235xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1236 xmlElementContentPtr content ATTRIBUTE_UNUSED,
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001237 int englob ATTRIBUTE_UNUSED) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001238}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001239#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001240
1241/**
1242 * xmlSnprintfElementContent:
1243 * @buf: an output buffer
1244 * @size: the buffer size
1245 * @content: An element table
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001246 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
Daniel Veillardd3d06722001-08-15 12:06:36 +00001247 *
Owen Taylor3473f882001-02-23 17:55:21 +00001248 * This will dump the content of the element content definition
1249 * Intended just for the debug routine
1250 */
1251void
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001252xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001253 int len;
1254
Owen Taylor3473f882001-02-23 17:55:21 +00001255 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001256 len = strlen(buf);
1257 if (size - len < 50) {
1258 if ((size - len > 4) && (buf[len - 1] != '.'))
1259 strcat(buf, " ...");
1260 return;
1261 }
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001262 if (englob) strcat(buf, "(");
Owen Taylor3473f882001-02-23 17:55:21 +00001263 switch (content->type) {
1264 case XML_ELEMENT_CONTENT_PCDATA:
1265 strcat(buf, "#PCDATA");
1266 break;
1267 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001268 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001269 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001270 strcat(buf, " ...");
1271 return;
1272 }
1273 strcat(buf, (char *) content->prefix);
1274 strcat(buf, ":");
1275 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001276 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001277 strcat(buf, " ...");
1278 return;
1279 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001280 if (content->name != NULL)
1281 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001282 break;
1283 case XML_ELEMENT_CONTENT_SEQ:
1284 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1285 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001286 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001287 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001288 xmlSnprintfElementContent(buf, size, content->c1, 0);
1289 len = strlen(buf);
1290 if (size - len < 50) {
1291 if ((size - len > 4) && (buf[len - 1] != '.'))
1292 strcat(buf, " ...");
1293 return;
1294 }
Owen Taylor3473f882001-02-23 17:55:21 +00001295 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001296 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1297 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1298 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001299 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001300 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001301 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001302 break;
1303 case XML_ELEMENT_CONTENT_OR:
1304 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1305 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001306 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001307 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001308 xmlSnprintfElementContent(buf, size, content->c1, 0);
1309 len = strlen(buf);
1310 if (size - len < 50) {
1311 if ((size - len > 4) && (buf[len - 1] != '.'))
1312 strcat(buf, " ...");
1313 return;
1314 }
Owen Taylor3473f882001-02-23 17:55:21 +00001315 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001316 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1317 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1318 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001319 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001320 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001321 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001322 break;
1323 }
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001324 if (englob)
Owen Taylor3473f882001-02-23 17:55:21 +00001325 strcat(buf, ")");
1326 switch (content->ocur) {
1327 case XML_ELEMENT_CONTENT_ONCE:
1328 break;
1329 case XML_ELEMENT_CONTENT_OPT:
1330 strcat(buf, "?");
1331 break;
1332 case XML_ELEMENT_CONTENT_MULT:
1333 strcat(buf, "*");
1334 break;
1335 case XML_ELEMENT_CONTENT_PLUS:
1336 strcat(buf, "+");
1337 break;
1338 }
1339}
1340
1341/****************************************************************
1342 * *
1343 * Registration of DTD declarations *
1344 * *
1345 ****************************************************************/
1346
1347/**
Owen Taylor3473f882001-02-23 17:55:21 +00001348 * xmlFreeElement:
1349 * @elem: An element
1350 *
1351 * Deallocate the memory used by an element definition
1352 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001353static void
Owen Taylor3473f882001-02-23 17:55:21 +00001354xmlFreeElement(xmlElementPtr elem) {
1355 if (elem == NULL) return;
1356 xmlUnlinkNode((xmlNodePtr) elem);
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001357 xmlFreeDocElementContent(elem->doc, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001358 if (elem->name != NULL)
1359 xmlFree((xmlChar *) elem->name);
1360 if (elem->prefix != NULL)
1361 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001362#ifdef LIBXML_REGEXP_ENABLED
1363 if (elem->contModel != NULL)
1364 xmlRegFreeRegexp(elem->contModel);
1365#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001366 xmlFree(elem);
1367}
1368
1369
1370/**
1371 * xmlAddElementDecl:
1372 * @ctxt: the validation context
1373 * @dtd: pointer to the DTD
1374 * @name: the entity name
1375 * @type: the element type
1376 * @content: the element content tree or NULL
1377 *
1378 * Register a new element declaration
1379 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001380 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001381 */
1382xmlElementPtr
William M. Brackedb65a72004-02-06 07:36:04 +00001383xmlAddElementDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001384 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001385 xmlElementTypeVal type,
1386 xmlElementContentPtr content) {
1387 xmlElementPtr ret;
1388 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001389 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001390 xmlChar *ns, *uqname;
1391
1392 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001393 return(NULL);
1394 }
1395 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001396 return(NULL);
1397 }
Daniel Veillard316a5c32005-01-23 22:56:39 +00001398
Owen Taylor3473f882001-02-23 17:55:21 +00001399 switch (type) {
1400 case XML_ELEMENT_TYPE_EMPTY:
1401 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001402 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1403 "xmlAddElementDecl: content != NULL for EMPTY\n",
1404 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001405 return(NULL);
1406 }
1407 break;
1408 case XML_ELEMENT_TYPE_ANY:
1409 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001410 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1411 "xmlAddElementDecl: content != NULL for ANY\n",
1412 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001413 return(NULL);
1414 }
1415 break;
1416 case XML_ELEMENT_TYPE_MIXED:
1417 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001418 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1419 "xmlAddElementDecl: content == NULL for MIXED\n",
1420 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001421 return(NULL);
1422 }
1423 break;
1424 case XML_ELEMENT_TYPE_ELEMENT:
1425 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001426 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1427 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1428 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001429 return(NULL);
1430 }
1431 break;
1432 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001433 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1434 "Internal: ELEMENT decl corrupted invalid type\n",
1435 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001436 return(NULL);
1437 }
1438
1439 /*
1440 * check if name is a QName
1441 */
1442 uqname = xmlSplitQName2(name, &ns);
1443 if (uqname != NULL)
1444 name = uqname;
1445
1446 /*
1447 * Create the Element table if needed.
1448 */
1449 table = (xmlElementTablePtr) dtd->elements;
1450 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00001451 xmlDictPtr dict = NULL;
1452
1453 if (dtd->doc != NULL)
1454 dict = dtd->doc->dict;
1455 table = xmlHashCreateDict(0, dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001456 dtd->elements = (void *) table;
1457 }
1458 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001459 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001460 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001461 if (uqname != NULL)
1462 xmlFree(uqname);
1463 if (ns != NULL)
1464 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001465 return(NULL);
1466 }
1467
Daniel Veillarda10efa82001-04-18 13:09:01 +00001468 /*
1469 * lookup old attributes inserted on an undefined element in the
1470 * internal subset.
1471 */
1472 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1473 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1474 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1475 oldAttributes = ret->attributes;
1476 ret->attributes = NULL;
1477 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1478 xmlFreeElement(ret);
1479 }
Owen Taylor3473f882001-02-23 17:55:21 +00001480 }
Owen Taylor3473f882001-02-23 17:55:21 +00001481
1482 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001483 * The element may already be present if one of its attribute
1484 * was registered first
1485 */
1486 ret = xmlHashLookup2(table, name, ns);
1487 if (ret != NULL) {
1488 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001489#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001490 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001491 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001492 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001493 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1494 "Redefinition of element %s\n",
1495 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001496#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001497 if (uqname != NULL)
1498 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001499 if (ns != NULL)
1500 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001501 return(NULL);
1502 }
William M. Brackd6e347e2005-04-15 01:34:41 +00001503 if (ns != NULL) {
1504 xmlFree(ns);
1505 ns = NULL;
1506 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001507 } else {
1508 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1509 if (ret == 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);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001515 return(NULL);
1516 }
1517 memset(ret, 0, sizeof(xmlElement));
1518 ret->type = XML_ELEMENT_DECL;
1519
1520 /*
1521 * fill the structure.
1522 */
1523 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001524 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001525 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001526 if (uqname != NULL)
1527 xmlFree(uqname);
1528 if (ns != NULL)
1529 xmlFree(ns);
1530 xmlFree(ret);
1531 return(NULL);
1532 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001533 ret->prefix = ns;
1534
1535 /*
1536 * Validity Check:
1537 * Insertion must not fail
1538 */
1539 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001540#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001541 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001542 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001543 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001544 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1545 "Redefinition of element %s\n",
1546 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001547#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001548 xmlFreeElement(ret);
1549 if (uqname != NULL)
1550 xmlFree(uqname);
1551 return(NULL);
1552 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001553 /*
1554 * For new element, may have attributes from earlier
1555 * definition in internal subset
1556 */
1557 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001558 }
1559
1560 /*
1561 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001562 */
1563 ret->etype = type;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001564 /*
1565 * Avoid a stupid copy when called by the parser
1566 * and flag it by setting a special parent value
1567 * so the parser doesn't unallocate it.
1568 */
Daniel Veillardc394f732005-01-26 00:04:52 +00001569 if ((ctxt != NULL) &&
1570 ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
1571 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001572 ret->content = content;
1573 if (content != NULL)
1574 content->parent = (xmlElementContentPtr) 1;
1575 } else {
1576 ret->content = xmlCopyDocElementContent(dtd->doc, content);
1577 }
Owen Taylor3473f882001-02-23 17:55:21 +00001578
1579 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001580 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001581 */
1582 ret->parent = dtd;
1583 ret->doc = dtd->doc;
1584 if (dtd->last == NULL) {
1585 dtd->children = dtd->last = (xmlNodePtr) ret;
1586 } else {
1587 dtd->last->next = (xmlNodePtr) ret;
1588 ret->prev = dtd->last;
1589 dtd->last = (xmlNodePtr) ret;
1590 }
1591 if (uqname != NULL)
1592 xmlFree(uqname);
1593 return(ret);
1594}
1595
1596/**
1597 * xmlFreeElementTable:
1598 * @table: An element table
1599 *
1600 * Deallocate the memory used by an element hash table.
1601 */
1602void
1603xmlFreeElementTable(xmlElementTablePtr table) {
1604 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1605}
1606
Daniel Veillard652327a2003-09-29 18:02:38 +00001607#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001608/**
1609 * xmlCopyElement:
1610 * @elem: An element
1611 *
1612 * Build a copy of an element.
1613 *
1614 * Returns the new xmlElementPtr or NULL in case of error.
1615 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001616static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001617xmlCopyElement(xmlElementPtr elem) {
1618 xmlElementPtr cur;
1619
1620 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1621 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001622 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001623 return(NULL);
1624 }
1625 memset(cur, 0, sizeof(xmlElement));
1626 cur->type = XML_ELEMENT_DECL;
1627 cur->etype = elem->etype;
1628 if (elem->name != NULL)
1629 cur->name = xmlStrdup(elem->name);
1630 else
1631 cur->name = NULL;
1632 if (elem->prefix != NULL)
1633 cur->prefix = xmlStrdup(elem->prefix);
1634 else
1635 cur->prefix = NULL;
1636 cur->content = xmlCopyElementContent(elem->content);
1637 /* TODO : rebuild the attribute list on the copy */
1638 cur->attributes = NULL;
1639 return(cur);
1640}
1641
1642/**
1643 * xmlCopyElementTable:
1644 * @table: An element table
1645 *
1646 * Build a copy of an element table.
1647 *
1648 * Returns the new xmlElementTablePtr or NULL in case of error.
1649 */
1650xmlElementTablePtr
1651xmlCopyElementTable(xmlElementTablePtr table) {
1652 return((xmlElementTablePtr) xmlHashCopy(table,
1653 (xmlHashCopier) xmlCopyElement));
1654}
Daniel Veillard652327a2003-09-29 18:02:38 +00001655#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001656
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001657#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001658/**
1659 * xmlDumpElementDecl:
1660 * @buf: the XML buffer output
1661 * @elem: An element table
1662 *
1663 * This will dump the content of the element declaration as an XML
1664 * DTD definition
1665 */
1666void
1667xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001668 if ((buf == NULL) || (elem == NULL))
1669 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001670 switch (elem->etype) {
1671 case XML_ELEMENT_TYPE_EMPTY:
1672 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001673 if (elem->prefix != NULL) {
1674 xmlBufferWriteCHAR(buf, elem->prefix);
1675 xmlBufferWriteChar(buf, ":");
1676 }
Owen Taylor3473f882001-02-23 17:55:21 +00001677 xmlBufferWriteCHAR(buf, elem->name);
1678 xmlBufferWriteChar(buf, " EMPTY>\n");
1679 break;
1680 case XML_ELEMENT_TYPE_ANY:
1681 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001682 if (elem->prefix != NULL) {
1683 xmlBufferWriteCHAR(buf, elem->prefix);
1684 xmlBufferWriteChar(buf, ":");
1685 }
Owen Taylor3473f882001-02-23 17:55:21 +00001686 xmlBufferWriteCHAR(buf, elem->name);
1687 xmlBufferWriteChar(buf, " ANY>\n");
1688 break;
1689 case XML_ELEMENT_TYPE_MIXED:
1690 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001691 if (elem->prefix != NULL) {
1692 xmlBufferWriteCHAR(buf, elem->prefix);
1693 xmlBufferWriteChar(buf, ":");
1694 }
Owen Taylor3473f882001-02-23 17:55:21 +00001695 xmlBufferWriteCHAR(buf, elem->name);
1696 xmlBufferWriteChar(buf, " ");
1697 xmlDumpElementContent(buf, elem->content, 1);
1698 xmlBufferWriteChar(buf, ">\n");
1699 break;
1700 case XML_ELEMENT_TYPE_ELEMENT:
1701 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001702 if (elem->prefix != NULL) {
1703 xmlBufferWriteCHAR(buf, elem->prefix);
1704 xmlBufferWriteChar(buf, ":");
1705 }
Owen Taylor3473f882001-02-23 17:55:21 +00001706 xmlBufferWriteCHAR(buf, elem->name);
1707 xmlBufferWriteChar(buf, " ");
1708 xmlDumpElementContent(buf, elem->content, 1);
1709 xmlBufferWriteChar(buf, ">\n");
1710 break;
1711 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001712 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1713 "Internal: ELEMENT struct corrupted invalid type\n",
1714 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001715 }
1716}
1717
1718/**
William M. Brack9e660592003-10-20 14:56:06 +00001719 * xmlDumpElementDeclScan:
1720 * @elem: An element table
1721 * @buf: the XML buffer output
1722 *
1723 * This routine is used by the hash scan function. It just reverses
1724 * the arguments.
1725 */
1726static void
1727xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1728 xmlDumpElementDecl(buf, elem);
1729}
1730
1731/**
Owen Taylor3473f882001-02-23 17:55:21 +00001732 * xmlDumpElementTable:
1733 * @buf: the XML buffer output
1734 * @table: An element table
1735 *
1736 * This will dump the content of the element table as an XML DTD definition
1737 */
1738void
1739xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001740 if ((buf == NULL) || (table == NULL))
1741 return;
William M. Brack9e660592003-10-20 14:56:06 +00001742 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001743}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001744#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001745
1746/**
1747 * xmlCreateEnumeration:
1748 * @name: the enumeration name or NULL
1749 *
1750 * create and initialize an enumeration attribute node.
1751 *
1752 * Returns the xmlEnumerationPtr just created or NULL in case
1753 * of error.
1754 */
1755xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001756xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001757 xmlEnumerationPtr ret;
1758
1759 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1760 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001761 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001762 return(NULL);
1763 }
1764 memset(ret, 0, sizeof(xmlEnumeration));
1765
1766 if (name != NULL)
1767 ret->name = xmlStrdup(name);
1768 return(ret);
1769}
1770
1771/**
1772 * xmlFreeEnumeration:
1773 * @cur: the tree to free.
1774 *
1775 * free an enumeration attribute node (recursive).
1776 */
1777void
1778xmlFreeEnumeration(xmlEnumerationPtr cur) {
1779 if (cur == NULL) return;
1780
1781 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1782
1783 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001784 xmlFree(cur);
1785}
1786
Daniel Veillard652327a2003-09-29 18:02:38 +00001787#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001788/**
1789 * xmlCopyEnumeration:
1790 * @cur: the tree to copy.
1791 *
1792 * Copy an enumeration attribute node (recursive).
1793 *
1794 * Returns the xmlEnumerationPtr just created or NULL in case
1795 * of error.
1796 */
1797xmlEnumerationPtr
1798xmlCopyEnumeration(xmlEnumerationPtr cur) {
1799 xmlEnumerationPtr ret;
1800
1801 if (cur == NULL) return(NULL);
1802 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1803
1804 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1805 else ret->next = NULL;
1806
1807 return(ret);
1808}
Daniel Veillard652327a2003-09-29 18:02:38 +00001809#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001810
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001811#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001812/**
1813 * xmlDumpEnumeration:
1814 * @buf: the XML buffer output
1815 * @enum: An enumeration
1816 *
1817 * This will dump the content of the enumeration
1818 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001819static void
Owen Taylor3473f882001-02-23 17:55:21 +00001820xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001821 if ((buf == NULL) || (cur == NULL))
1822 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001823
1824 xmlBufferWriteCHAR(buf, cur->name);
1825 if (cur->next == NULL)
1826 xmlBufferWriteChar(buf, ")");
1827 else {
1828 xmlBufferWriteChar(buf, " | ");
1829 xmlDumpEnumeration(buf, cur->next);
1830 }
1831}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001832#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001833
Daniel Veillard4432df22003-09-28 18:58:27 +00001834#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001835/**
1836 * xmlScanAttributeDeclCallback:
1837 * @attr: the attribute decl
1838 * @list: the list to update
1839 *
1840 * Callback called by xmlScanAttributeDecl when a new attribute
1841 * has to be entered in the list.
1842 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001843static void
Owen Taylor3473f882001-02-23 17:55:21 +00001844xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001845 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001846 attr->nexth = *list;
1847 *list = attr;
1848}
1849
1850/**
1851 * xmlScanAttributeDecl:
1852 * @dtd: pointer to the DTD
1853 * @elem: the element name
1854 *
1855 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001856 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001857 *
1858 * Returns the pointer to the first attribute decl in the chain,
1859 * possibly NULL.
1860 */
1861xmlAttributePtr
1862xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1863 xmlAttributePtr ret = NULL;
1864 xmlAttributeTablePtr table;
1865
1866 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001867 return(NULL);
1868 }
1869 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001870 return(NULL);
1871 }
1872 table = (xmlAttributeTablePtr) dtd->attributes;
1873 if (table == NULL)
1874 return(NULL);
1875
1876 /* WRONG !!! */
1877 xmlHashScan3(table, NULL, NULL, elem,
1878 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1879 return(ret);
1880}
1881
1882/**
1883 * xmlScanIDAttributeDecl:
1884 * @ctxt: the validation context
1885 * @elem: the element name
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001886 * @err: whether to raise errors here
Owen Taylor3473f882001-02-23 17:55:21 +00001887 *
1888 * Verify that the element don't have too many ID attributes
1889 * declared.
1890 *
1891 * Returns the number of ID attributes found.
1892 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001893static int
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001894xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
Owen Taylor3473f882001-02-23 17:55:21 +00001895 xmlAttributePtr cur;
1896 int ret = 0;
1897
1898 if (elem == NULL) return(0);
1899 cur = elem->attributes;
1900 while (cur != NULL) {
1901 if (cur->atype == XML_ATTRIBUTE_ID) {
1902 ret ++;
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001903 if ((ret > 1) && (err))
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001904 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001905 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001906 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001907 }
1908 cur = cur->nexth;
1909 }
1910 return(ret);
1911}
Daniel Veillard4432df22003-09-28 18:58:27 +00001912#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001913
1914/**
1915 * xmlFreeAttribute:
1916 * @elem: An attribute
1917 *
1918 * Deallocate the memory used by an attribute definition
1919 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001920static void
Owen Taylor3473f882001-02-23 17:55:21 +00001921xmlFreeAttribute(xmlAttributePtr attr) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001922 xmlDictPtr dict;
1923
Owen Taylor3473f882001-02-23 17:55:21 +00001924 if (attr == NULL) return;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001925 if (attr->doc != NULL)
1926 dict = attr->doc->dict;
1927 else
1928 dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001929 xmlUnlinkNode((xmlNodePtr) attr);
1930 if (attr->tree != NULL)
1931 xmlFreeEnumeration(attr->tree);
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001932 if (dict) {
1933 if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1934 xmlFree((xmlChar *) attr->elem);
1935 if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1936 xmlFree((xmlChar *) attr->name);
1937 if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1938 xmlFree((xmlChar *) attr->prefix);
1939 if ((attr->defaultValue != NULL) &&
1940 (!xmlDictOwns(dict, attr->defaultValue)))
1941 xmlFree((xmlChar *) attr->defaultValue);
1942 } else {
1943 if (attr->elem != NULL)
1944 xmlFree((xmlChar *) attr->elem);
1945 if (attr->name != NULL)
1946 xmlFree((xmlChar *) attr->name);
1947 if (attr->defaultValue != NULL)
1948 xmlFree((xmlChar *) attr->defaultValue);
1949 if (attr->prefix != NULL)
1950 xmlFree((xmlChar *) attr->prefix);
1951 }
Owen Taylor3473f882001-02-23 17:55:21 +00001952 xmlFree(attr);
1953}
1954
1955
1956/**
1957 * xmlAddAttributeDecl:
1958 * @ctxt: the validation context
1959 * @dtd: pointer to the DTD
1960 * @elem: the element name
1961 * @name: the attribute name
1962 * @ns: the attribute namespace prefix
1963 * @type: the attribute type
1964 * @def: the attribute default type
1965 * @defaultValue: the attribute default value
1966 * @tree: if it's an enumeration, the associated list
1967 *
1968 * Register a new attribute declaration
1969 * Note that @tree becomes the ownership of the DTD
1970 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001971 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001972 */
1973xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001974xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001975 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001976 const xmlChar *name, const xmlChar *ns,
1977 xmlAttributeType type, xmlAttributeDefault def,
1978 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1979 xmlAttributePtr ret;
1980 xmlAttributeTablePtr table;
1981 xmlElementPtr elemDef;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001982 xmlDictPtr dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001983
1984 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001985 xmlFreeEnumeration(tree);
1986 return(NULL);
1987 }
1988 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001989 xmlFreeEnumeration(tree);
1990 return(NULL);
1991 }
1992 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001993 xmlFreeEnumeration(tree);
1994 return(NULL);
1995 }
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001996 if (dtd->doc != NULL)
1997 dict = dtd->doc->dict;
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001998
Daniel Veillard4432df22003-09-28 18:58:27 +00001999#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002000 /*
2001 * Check the type and possibly the default value.
2002 */
2003 switch (type) {
2004 case XML_ATTRIBUTE_CDATA:
2005 break;
2006 case XML_ATTRIBUTE_ID:
2007 break;
2008 case XML_ATTRIBUTE_IDREF:
2009 break;
2010 case XML_ATTRIBUTE_IDREFS:
2011 break;
2012 case XML_ATTRIBUTE_ENTITY:
2013 break;
2014 case XML_ATTRIBUTE_ENTITIES:
2015 break;
2016 case XML_ATTRIBUTE_NMTOKEN:
2017 break;
2018 case XML_ATTRIBUTE_NMTOKENS:
2019 break;
2020 case XML_ATTRIBUTE_ENUMERATION:
2021 break;
2022 case XML_ATTRIBUTE_NOTATION:
2023 break;
2024 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002025 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
2026 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2027 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002028 xmlFreeEnumeration(tree);
2029 return(NULL);
2030 }
2031 if ((defaultValue != NULL) &&
Daniel Veillardae0765b2008-07-31 19:54:59 +00002032 (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002033 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
2034 "Attribute %s of %s: invalid default value\n",
2035 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00002036 defaultValue = NULL;
Daniel Veillard42595322004-11-08 10:52:06 +00002037 if (ctxt != NULL)
2038 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002039 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002040#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002041
2042 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00002043 * Check first that an attribute defined in the external subset wasn't
2044 * already defined in the internal subset
2045 */
2046 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2047 (dtd->doc->intSubset != NULL) &&
2048 (dtd->doc->intSubset->attributes != NULL)) {
2049 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
Daniel Veillardae0765b2008-07-31 19:54:59 +00002050 if (ret != NULL) {
2051 xmlFreeEnumeration(tree);
Daniel Veillardd85f4f42002-03-25 10:48:46 +00002052 return(NULL);
Daniel Veillardae0765b2008-07-31 19:54:59 +00002053 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00002054 }
2055
2056 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002057 * Create the Attribute table if needed.
2058 */
2059 table = (xmlAttributeTablePtr) dtd->attributes;
2060 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00002061 table = xmlHashCreateDict(0, dict);
Owen Taylor3473f882001-02-23 17:55:21 +00002062 dtd->attributes = (void *) table;
2063 }
2064 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002065 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002066 "xmlAddAttributeDecl: Table creation failed!\n");
Daniel Veillardae0765b2008-07-31 19:54:59 +00002067 xmlFreeEnumeration(tree);
Owen Taylor3473f882001-02-23 17:55:21 +00002068 return(NULL);
2069 }
2070
2071
2072 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2073 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002074 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardae0765b2008-07-31 19:54:59 +00002075 xmlFreeEnumeration(tree);
Owen Taylor3473f882001-02-23 17:55:21 +00002076 return(NULL);
2077 }
2078 memset(ret, 0, sizeof(xmlAttribute));
2079 ret->type = XML_ATTRIBUTE_DECL;
2080
2081 /*
2082 * fill the structure.
2083 */
2084 ret->atype = type;
William M. Brackf810de02005-07-06 22:48:41 +00002085 /*
2086 * doc must be set before possible error causes call
2087 * to xmlFreeAttribute (because it's used to check on
2088 * dict use)
2089 */
2090 ret->doc = dtd->doc;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002091 if (dict) {
2092 ret->name = xmlDictLookup(dict, name, -1);
2093 ret->prefix = xmlDictLookup(dict, ns, -1);
2094 ret->elem = xmlDictLookup(dict, elem, -1);
2095 } else {
2096 ret->name = xmlStrdup(name);
2097 ret->prefix = xmlStrdup(ns);
2098 ret->elem = xmlStrdup(elem);
2099 }
Owen Taylor3473f882001-02-23 17:55:21 +00002100 ret->def = def;
2101 ret->tree = tree;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002102 if (defaultValue != NULL) {
2103 if (dict)
2104 ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2105 else
2106 ret->defaultValue = xmlStrdup(defaultValue);
2107 }
Owen Taylor3473f882001-02-23 17:55:21 +00002108
2109 /*
2110 * Validity Check:
2111 * Search the DTD for previous declarations of the ATTLIST
2112 */
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002113 if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002114#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002115 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002116 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002117 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002118 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00002119 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002120 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00002121#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002122 xmlFreeAttribute(ret);
2123 return(NULL);
2124 }
2125
2126 /*
2127 * Validity Check:
2128 * Multiple ID per element
2129 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00002130 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002131 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00002132
Daniel Veillard4432df22003-09-28 18:58:27 +00002133#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002134 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillarddbee0f12005-06-27 13:42:57 +00002135 (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002136 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00002137 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002138 elem, name, NULL);
Daniel Veillard42595322004-11-08 10:52:06 +00002139 if (ctxt != NULL)
2140 ctxt->valid = 0;
Daniel Veillardc7612992002-02-17 22:47:37 +00002141 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002142#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00002143
Daniel Veillard48da9102001-08-07 01:10:10 +00002144 /*
2145 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002146 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00002147 */
2148 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2149 ((ret->prefix != NULL &&
2150 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2151 ret->nexth = elemDef->attributes;
2152 elemDef->attributes = ret;
2153 } else {
2154 xmlAttributePtr tmp = elemDef->attributes;
2155
2156 while ((tmp != NULL) &&
2157 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2158 ((ret->prefix != NULL &&
2159 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2160 if (tmp->nexth == NULL)
2161 break;
2162 tmp = tmp->nexth;
2163 }
2164 if (tmp != NULL) {
2165 ret->nexth = tmp->nexth;
2166 tmp->nexth = ret;
2167 } else {
2168 ret->nexth = elemDef->attributes;
2169 elemDef->attributes = ret;
2170 }
2171 }
Owen Taylor3473f882001-02-23 17:55:21 +00002172 }
2173
2174 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002175 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00002176 */
2177 ret->parent = dtd;
Owen Taylor3473f882001-02-23 17:55:21 +00002178 if (dtd->last == NULL) {
2179 dtd->children = dtd->last = (xmlNodePtr) ret;
2180 } else {
2181 dtd->last->next = (xmlNodePtr) ret;
2182 ret->prev = dtd->last;
2183 dtd->last = (xmlNodePtr) ret;
2184 }
2185 return(ret);
2186}
2187
2188/**
2189 * xmlFreeAttributeTable:
2190 * @table: An attribute table
2191 *
2192 * Deallocate the memory used by an entities hash table.
2193 */
2194void
2195xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2196 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
2197}
2198
Daniel Veillard652327a2003-09-29 18:02:38 +00002199#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002200/**
2201 * xmlCopyAttribute:
2202 * @attr: An attribute
2203 *
2204 * Build a copy of an attribute.
2205 *
2206 * Returns the new xmlAttributePtr or NULL in case of error.
2207 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002208static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002209xmlCopyAttribute(xmlAttributePtr attr) {
2210 xmlAttributePtr cur;
2211
2212 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2213 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002214 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002215 return(NULL);
2216 }
2217 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00002218 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00002219 cur->atype = attr->atype;
2220 cur->def = attr->def;
2221 cur->tree = xmlCopyEnumeration(attr->tree);
2222 if (attr->elem != NULL)
2223 cur->elem = xmlStrdup(attr->elem);
2224 if (attr->name != NULL)
2225 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002226 if (attr->prefix != NULL)
2227 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002228 if (attr->defaultValue != NULL)
2229 cur->defaultValue = xmlStrdup(attr->defaultValue);
2230 return(cur);
2231}
2232
2233/**
2234 * xmlCopyAttributeTable:
2235 * @table: An attribute table
2236 *
2237 * Build a copy of an attribute table.
2238 *
2239 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2240 */
2241xmlAttributeTablePtr
2242xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2243 return((xmlAttributeTablePtr) xmlHashCopy(table,
2244 (xmlHashCopier) xmlCopyAttribute));
2245}
Daniel Veillard652327a2003-09-29 18:02:38 +00002246#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002247
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002248#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002249/**
2250 * xmlDumpAttributeDecl:
2251 * @buf: the XML buffer output
2252 * @attr: An attribute declaration
2253 *
2254 * This will dump the content of the attribute declaration as an XML
2255 * DTD definition
2256 */
2257void
2258xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002259 if ((buf == NULL) || (attr == NULL))
2260 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002261 xmlBufferWriteChar(buf, "<!ATTLIST ");
2262 xmlBufferWriteCHAR(buf, attr->elem);
2263 xmlBufferWriteChar(buf, " ");
2264 if (attr->prefix != NULL) {
2265 xmlBufferWriteCHAR(buf, attr->prefix);
2266 xmlBufferWriteChar(buf, ":");
2267 }
2268 xmlBufferWriteCHAR(buf, attr->name);
2269 switch (attr->atype) {
2270 case XML_ATTRIBUTE_CDATA:
2271 xmlBufferWriteChar(buf, " CDATA");
2272 break;
2273 case XML_ATTRIBUTE_ID:
2274 xmlBufferWriteChar(buf, " ID");
2275 break;
2276 case XML_ATTRIBUTE_IDREF:
2277 xmlBufferWriteChar(buf, " IDREF");
2278 break;
2279 case XML_ATTRIBUTE_IDREFS:
2280 xmlBufferWriteChar(buf, " IDREFS");
2281 break;
2282 case XML_ATTRIBUTE_ENTITY:
2283 xmlBufferWriteChar(buf, " ENTITY");
2284 break;
2285 case XML_ATTRIBUTE_ENTITIES:
2286 xmlBufferWriteChar(buf, " ENTITIES");
2287 break;
2288 case XML_ATTRIBUTE_NMTOKEN:
2289 xmlBufferWriteChar(buf, " NMTOKEN");
2290 break;
2291 case XML_ATTRIBUTE_NMTOKENS:
2292 xmlBufferWriteChar(buf, " NMTOKENS");
2293 break;
2294 case XML_ATTRIBUTE_ENUMERATION:
2295 xmlBufferWriteChar(buf, " (");
2296 xmlDumpEnumeration(buf, attr->tree);
2297 break;
2298 case XML_ATTRIBUTE_NOTATION:
2299 xmlBufferWriteChar(buf, " NOTATION (");
2300 xmlDumpEnumeration(buf, attr->tree);
2301 break;
2302 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002303 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2304 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2305 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002306 }
2307 switch (attr->def) {
2308 case XML_ATTRIBUTE_NONE:
2309 break;
2310 case XML_ATTRIBUTE_REQUIRED:
2311 xmlBufferWriteChar(buf, " #REQUIRED");
2312 break;
2313 case XML_ATTRIBUTE_IMPLIED:
2314 xmlBufferWriteChar(buf, " #IMPLIED");
2315 break;
2316 case XML_ATTRIBUTE_FIXED:
2317 xmlBufferWriteChar(buf, " #FIXED");
2318 break;
2319 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002320 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2321 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2322 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002323 }
2324 if (attr->defaultValue != NULL) {
2325 xmlBufferWriteChar(buf, " ");
2326 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2327 }
2328 xmlBufferWriteChar(buf, ">\n");
2329}
2330
2331/**
William M. Brack9e660592003-10-20 14:56:06 +00002332 * xmlDumpAttributeDeclScan:
2333 * @attr: An attribute declaration
2334 * @buf: the XML buffer output
2335 *
2336 * This is used with the hash scan function - just reverses arguments
2337 */
2338static void
2339xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2340 xmlDumpAttributeDecl(buf, attr);
2341}
2342
2343/**
Owen Taylor3473f882001-02-23 17:55:21 +00002344 * xmlDumpAttributeTable:
2345 * @buf: the XML buffer output
2346 * @table: An attribute table
2347 *
2348 * This will dump the content of the attribute table as an XML DTD definition
2349 */
2350void
2351xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002352 if ((buf == NULL) || (table == NULL))
2353 return;
William M. Brack9e660592003-10-20 14:56:06 +00002354 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002355}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002356#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002357
2358/************************************************************************
2359 * *
2360 * NOTATIONs *
2361 * *
2362 ************************************************************************/
2363/**
Owen Taylor3473f882001-02-23 17:55:21 +00002364 * xmlFreeNotation:
2365 * @not: A notation
2366 *
2367 * Deallocate the memory used by an notation definition
2368 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002369static void
Owen Taylor3473f882001-02-23 17:55:21 +00002370xmlFreeNotation(xmlNotationPtr nota) {
2371 if (nota == NULL) return;
2372 if (nota->name != NULL)
2373 xmlFree((xmlChar *) nota->name);
2374 if (nota->PublicID != NULL)
2375 xmlFree((xmlChar *) nota->PublicID);
2376 if (nota->SystemID != NULL)
2377 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002378 xmlFree(nota);
2379}
2380
2381
2382/**
2383 * xmlAddNotationDecl:
2384 * @dtd: pointer to the DTD
2385 * @ctxt: the validation context
2386 * @name: the entity name
2387 * @PublicID: the public identifier or NULL
2388 * @SystemID: the system identifier or NULL
2389 *
2390 * Register a new notation declaration
2391 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002392 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002393 */
2394xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002395xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002396 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002397 const xmlChar *PublicID, const xmlChar *SystemID) {
2398 xmlNotationPtr ret;
2399 xmlNotationTablePtr table;
2400
2401 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002402 return(NULL);
2403 }
2404 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002405 return(NULL);
2406 }
2407 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002408 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002409 }
2410
2411 /*
2412 * Create the Notation table if needed.
2413 */
2414 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002415 if (table == NULL) {
2416 xmlDictPtr dict = NULL;
2417 if (dtd->doc != NULL)
2418 dict = dtd->doc->dict;
2419
2420 dtd->notations = table = xmlHashCreateDict(0, dict);
2421 }
Owen Taylor3473f882001-02-23 17:55:21 +00002422 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002423 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002424 "xmlAddNotationDecl: Table creation failed!\n");
2425 return(NULL);
2426 }
2427
2428 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2429 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002430 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002431 return(NULL);
2432 }
2433 memset(ret, 0, sizeof(xmlNotation));
2434
2435 /*
2436 * fill the structure.
2437 */
2438 ret->name = xmlStrdup(name);
2439 if (SystemID != NULL)
2440 ret->SystemID = xmlStrdup(SystemID);
2441 if (PublicID != NULL)
2442 ret->PublicID = xmlStrdup(PublicID);
2443
2444 /*
2445 * Validity Check:
2446 * Check the DTD for previous declarations of the ATTLIST
2447 */
2448 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002449#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002450 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2451 "xmlAddNotationDecl: %s already defined\n",
2452 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002453#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002454 xmlFreeNotation(ret);
2455 return(NULL);
2456 }
2457 return(ret);
2458}
2459
2460/**
2461 * xmlFreeNotationTable:
2462 * @table: An notation table
2463 *
2464 * Deallocate the memory used by an entities hash table.
2465 */
2466void
2467xmlFreeNotationTable(xmlNotationTablePtr table) {
2468 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2469}
2470
Daniel Veillard652327a2003-09-29 18:02:38 +00002471#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002472/**
2473 * xmlCopyNotation:
2474 * @nota: A notation
2475 *
2476 * Build a copy of a notation.
2477 *
2478 * Returns the new xmlNotationPtr or NULL in case of error.
2479 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002480static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002481xmlCopyNotation(xmlNotationPtr nota) {
2482 xmlNotationPtr cur;
2483
2484 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2485 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002486 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002487 return(NULL);
2488 }
2489 if (nota->name != NULL)
2490 cur->name = xmlStrdup(nota->name);
2491 else
2492 cur->name = NULL;
2493 if (nota->PublicID != NULL)
2494 cur->PublicID = xmlStrdup(nota->PublicID);
2495 else
2496 cur->PublicID = NULL;
2497 if (nota->SystemID != NULL)
2498 cur->SystemID = xmlStrdup(nota->SystemID);
2499 else
2500 cur->SystemID = NULL;
2501 return(cur);
2502}
2503
2504/**
2505 * xmlCopyNotationTable:
2506 * @table: A notation table
2507 *
2508 * Build a copy of a notation table.
2509 *
2510 * Returns the new xmlNotationTablePtr or NULL in case of error.
2511 */
2512xmlNotationTablePtr
2513xmlCopyNotationTable(xmlNotationTablePtr table) {
2514 return((xmlNotationTablePtr) xmlHashCopy(table,
2515 (xmlHashCopier) xmlCopyNotation));
2516}
Daniel Veillard652327a2003-09-29 18:02:38 +00002517#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002518
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002519#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002520/**
2521 * xmlDumpNotationDecl:
2522 * @buf: the XML buffer output
2523 * @nota: A notation declaration
2524 *
2525 * This will dump the content the notation declaration as an XML DTD definition
2526 */
2527void
2528xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002529 if ((buf == NULL) || (nota == NULL))
2530 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002531 xmlBufferWriteChar(buf, "<!NOTATION ");
2532 xmlBufferWriteCHAR(buf, nota->name);
2533 if (nota->PublicID != NULL) {
2534 xmlBufferWriteChar(buf, " PUBLIC ");
2535 xmlBufferWriteQuotedString(buf, nota->PublicID);
2536 if (nota->SystemID != NULL) {
2537 xmlBufferWriteChar(buf, " ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002538 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002539 }
2540 } else {
2541 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002542 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002543 }
2544 xmlBufferWriteChar(buf, " >\n");
2545}
2546
2547/**
William M. Brack9e660592003-10-20 14:56:06 +00002548 * xmlDumpNotationDeclScan:
2549 * @nota: A notation declaration
2550 * @buf: the XML buffer output
2551 *
2552 * This is called with the hash scan function, and just reverses args
2553 */
2554static void
2555xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2556 xmlDumpNotationDecl(buf, nota);
2557}
2558
2559/**
Owen Taylor3473f882001-02-23 17:55:21 +00002560 * xmlDumpNotationTable:
2561 * @buf: the XML buffer output
2562 * @table: A notation table
2563 *
2564 * This will dump the content of the notation table as an XML DTD definition
2565 */
2566void
2567xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002568 if ((buf == NULL) || (table == NULL))
2569 return;
William M. Brack9e660592003-10-20 14:56:06 +00002570 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002571}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002572#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002573
2574/************************************************************************
2575 * *
2576 * IDs *
2577 * *
2578 ************************************************************************/
2579/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002580 * DICT_FREE:
2581 * @str: a string
2582 *
2583 * Free a string if it is not owned by the "dict" dictionnary in the
2584 * current scope
2585 */
2586#define DICT_FREE(str) \
2587 if ((str) && ((!dict) || \
2588 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2589 xmlFree((char *)(str));
2590
2591/**
Owen Taylor3473f882001-02-23 17:55:21 +00002592 * xmlFreeID:
2593 * @not: A id
2594 *
2595 * Deallocate the memory used by an id definition
2596 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002597static void
Owen Taylor3473f882001-02-23 17:55:21 +00002598xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002599 xmlDictPtr dict = NULL;
2600
Owen Taylor3473f882001-02-23 17:55:21 +00002601 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002602
2603 if (id->doc != NULL)
2604 dict = id->doc->dict;
2605
Owen Taylor3473f882001-02-23 17:55:21 +00002606 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002607 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002608 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002609 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002610 xmlFree(id);
2611}
2612
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002613
Owen Taylor3473f882001-02-23 17:55:21 +00002614/**
2615 * xmlAddID:
2616 * @ctxt: the validation context
2617 * @doc: pointer to the document
2618 * @value: the value name
2619 * @attr: the attribute holding the ID
2620 *
2621 * Register a new id declaration
2622 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002623 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002624 */
2625xmlIDPtr
2626xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2627 xmlAttrPtr attr) {
2628 xmlIDPtr ret;
2629 xmlIDTablePtr table;
2630
2631 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002632 return(NULL);
2633 }
2634 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002635 return(NULL);
2636 }
2637 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002638 return(NULL);
2639 }
2640
2641 /*
2642 * Create the ID table if needed.
2643 */
2644 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002645 if (table == NULL) {
2646 doc->ids = table = xmlHashCreateDict(0, doc->dict);
2647 }
Owen Taylor3473f882001-02-23 17:55:21 +00002648 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002649 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002650 "xmlAddID: Table creation failed!\n");
2651 return(NULL);
2652 }
2653
2654 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2655 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002656 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002657 return(NULL);
2658 }
2659
2660 /*
2661 * fill the structure.
2662 */
2663 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002664 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002665 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2666 /*
2667 * Operating in streaming mode, attr is gonna disapear
2668 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002669 if (doc->dict != NULL)
2670 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2671 else
2672 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002673 ret->attr = NULL;
2674 } else {
2675 ret->attr = attr;
2676 ret->name = NULL;
2677 }
2678 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002679
2680 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002681#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002682 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002683 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002684 */
Daniel Veillardd3669b22004-02-25 12:34:55 +00002685 if ((ctxt != NULL) && (ctxt->error != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002686 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2687 "ID %s already defined\n",
2688 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002689 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002690#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002691 xmlFreeID(ret);
2692 return(NULL);
2693 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002694 if (attr != NULL)
2695 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002696 return(ret);
2697}
2698
2699/**
2700 * xmlFreeIDTable:
2701 * @table: An id table
2702 *
2703 * Deallocate the memory used by an ID hash table.
2704 */
2705void
2706xmlFreeIDTable(xmlIDTablePtr table) {
2707 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2708}
2709
2710/**
2711 * xmlIsID:
2712 * @doc: the document
2713 * @elem: the element carrying the attribute
2714 * @attr: the attribute
2715 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002716 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002717 * then this is done if DTD loading has been requested. In the case
2718 * of HTML documents parsed with the HTML parser, then ID detection is
2719 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002720 *
2721 * Returns 0 or 1 depending on the lookup result
2722 */
2723int
2724xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00002725 if ((attr == NULL) || (attr->name == NULL)) return(0);
2726 if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2727 (!strcmp((char *) attr->name, "id")) &&
2728 (!strcmp((char *) attr->ns->prefix, "xml")))
2729 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002730 if (doc == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002731 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2732 return(0);
2733 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Rob Richards04bffc02006-03-03 16:44:37 +00002734 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2735 ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
Daniel Veillard38431c32007-06-12 16:20:09 +00002736 ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
Owen Taylor3473f882001-02-23 17:55:21 +00002737 return(1);
2738 return(0);
Daniel Veillard379a3b72005-08-12 10:18:14 +00002739 } else if (elem == NULL) {
2740 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002741 } else {
Daniel Veillard465a0002005-08-22 12:07:04 +00002742 xmlAttributePtr attrDecl = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002743
Daniel Veillard379a3b72005-08-12 10:18:14 +00002744 xmlChar felem[50], fattr[50];
2745 xmlChar *fullelemname, *fullattrname;
2746
2747 fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2748 xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2749 (xmlChar *)elem->name;
2750
2751 fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2752 xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2753 (xmlChar *)attr->name;
2754
2755 if (fullelemname != NULL && fullattrname != NULL) {
2756 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2757 fullattrname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002758 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillard379a3b72005-08-12 10:18:14 +00002759 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2760 fullattrname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002761 }
Owen Taylor3473f882001-02-23 17:55:21 +00002762
Daniel Veillard379a3b72005-08-12 10:18:14 +00002763 if ((fullattrname != fattr) && (fullattrname != attr->name))
2764 xmlFree(fullattrname);
2765 if ((fullelemname != felem) && (fullelemname != elem->name))
2766 xmlFree(fullelemname);
2767
Owen Taylor3473f882001-02-23 17:55:21 +00002768 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2769 return(1);
2770 }
2771 return(0);
2772}
2773
2774/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002775 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002776 * @doc: the document
2777 * @attr: the attribute
2778 *
2779 * Remove the given attribute from the ID table maintained internally.
2780 *
2781 * Returns -1 if the lookup failed and 0 otherwise
2782 */
2783int
2784xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002785 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002786 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002787 xmlChar *ID;
2788
2789 if (doc == NULL) return(-1);
2790 if (attr == NULL) return(-1);
2791 table = (xmlIDTablePtr) doc->ids;
2792 if (table == NULL)
2793 return(-1);
2794
2795 if (attr == NULL)
2796 return(-1);
2797 ID = xmlNodeListGetString(doc, attr->children, 1);
2798 if (ID == NULL)
2799 return(-1);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002800 id = xmlHashLookup(table, ID);
2801 if (id == NULL || id->attr != attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002802 xmlFree(ID);
2803 return(-1);
2804 }
Daniel Veillard91b955c2004-12-10 10:26:42 +00002805 xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID);
Owen Taylor3473f882001-02-23 17:55:21 +00002806 xmlFree(ID);
Daniel Veillardda6f4af2005-06-20 17:17:54 +00002807 attr->atype = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002808 return(0);
2809}
2810
2811/**
2812 * xmlGetID:
2813 * @doc: pointer to the document
2814 * @ID: the ID value
2815 *
2816 * Search the attribute declaring the given ID
2817 *
2818 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2819 */
2820xmlAttrPtr
2821xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2822 xmlIDTablePtr table;
2823 xmlIDPtr id;
2824
2825 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002826 return(NULL);
2827 }
2828
2829 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002830 return(NULL);
2831 }
2832
2833 table = (xmlIDTablePtr) doc->ids;
2834 if (table == NULL)
2835 return(NULL);
2836
2837 id = xmlHashLookup(table, ID);
2838 if (id == NULL)
2839 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002840 if (id->attr == NULL) {
2841 /*
2842 * We are operating on a stream, return a well known reference
2843 * since the attribute node doesn't exist anymore
2844 */
2845 return((xmlAttrPtr) doc);
2846 }
Owen Taylor3473f882001-02-23 17:55:21 +00002847 return(id->attr);
2848}
2849
2850/************************************************************************
2851 * *
2852 * Refs *
2853 * *
2854 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002855typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002856{
2857 xmlListPtr l;
2858 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002859} xmlRemoveMemo;
2860
2861typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2862
2863typedef struct xmlValidateMemo_t
2864{
2865 xmlValidCtxtPtr ctxt;
2866 const xmlChar *name;
2867} xmlValidateMemo;
2868
2869typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002870
2871/**
Owen Taylor3473f882001-02-23 17:55:21 +00002872 * xmlFreeRef:
2873 * @lk: A list link
2874 *
2875 * Deallocate the memory used by a ref definition
2876 */
2877static void
2878xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002879 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2880 if (ref == NULL) return;
2881 if (ref->value != NULL)
2882 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002883 if (ref->name != NULL)
2884 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002885 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002886}
2887
2888/**
2889 * xmlFreeRefList:
2890 * @list_ref: A list of references.
2891 *
2892 * Deallocate the memory used by a list of references
2893 */
2894static void
2895xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002896 if (list_ref == NULL) return;
2897 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002898}
2899
2900/**
2901 * xmlWalkRemoveRef:
2902 * @data: Contents of current link
2903 * @user: Value supplied by the user
2904 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002905 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002906 */
2907static int
2908xmlWalkRemoveRef(const void *data, const void *user)
2909{
Daniel Veillard37721922001-05-04 15:21:12 +00002910 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2911 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2912 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002913
Daniel Veillard37721922001-05-04 15:21:12 +00002914 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2915 xmlListRemoveFirst(ref_list, (void *)data);
2916 return 0;
2917 }
2918 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002919}
2920
2921/**
Daniel Veillard770075b2004-02-25 10:44:30 +00002922 * xmlDummyCompare
2923 * @data0: Value supplied by the user
2924 * @data1: Value supplied by the user
2925 *
2926 * Do nothing, return 0. Used to create unordered lists.
2927 */
2928static int
Daniel Veillardf54cd532004-02-25 11:52:31 +00002929xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2930 const void *data1 ATTRIBUTE_UNUSED)
Daniel Veillard770075b2004-02-25 10:44:30 +00002931{
2932 return (0);
2933}
2934
2935/**
Owen Taylor3473f882001-02-23 17:55:21 +00002936 * xmlAddRef:
2937 * @ctxt: the validation context
2938 * @doc: pointer to the document
2939 * @value: the value name
2940 * @attr: the attribute holding the Ref
2941 *
2942 * Register a new ref declaration
2943 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002944 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002945 */
2946xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002947xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002948 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002949 xmlRefPtr ret;
2950 xmlRefTablePtr table;
2951 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002952
Daniel Veillard37721922001-05-04 15:21:12 +00002953 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002954 return(NULL);
2955 }
2956 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002957 return(NULL);
2958 }
2959 if (attr == NULL) {
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 * Create the Ref table if needed.
2965 */
Daniel Veillard37721922001-05-04 15:21:12 +00002966 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002967 if (table == NULL) {
2968 doc->refs = table = xmlHashCreateDict(0, doc->dict);
2969 }
Daniel Veillard37721922001-05-04 15:21:12 +00002970 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002971 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002972 "xmlAddRef: Table creation failed!\n");
2973 return(NULL);
2974 }
Owen Taylor3473f882001-02-23 17:55:21 +00002975
Daniel Veillard37721922001-05-04 15:21:12 +00002976 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2977 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002978 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002979 return(NULL);
2980 }
Owen Taylor3473f882001-02-23 17:55:21 +00002981
Daniel Veillard37721922001-05-04 15:21:12 +00002982 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002983 * fill the structure.
2984 */
Daniel Veillard37721922001-05-04 15:21:12 +00002985 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002986 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2987 /*
2988 * Operating in streaming mode, attr is gonna disapear
2989 */
2990 ret->name = xmlStrdup(attr->name);
2991 ret->attr = NULL;
2992 } else {
2993 ret->name = NULL;
2994 ret->attr = attr;
2995 }
2996 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002997
Daniel Veillard37721922001-05-04 15:21:12 +00002998 /* To add a reference :-
2999 * References are maintained as a list of references,
3000 * Lookup the entry, if no entry create new nodelist
3001 * Add the owning node to the NodeList
3002 * Return the ref
3003 */
Owen Taylor3473f882001-02-23 17:55:21 +00003004
Daniel Veillard37721922001-05-04 15:21:12 +00003005 if (NULL == (ref_list = xmlHashLookup(table, value))) {
Daniel Veillard770075b2004-02-25 10:44:30 +00003006 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00003007 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3008 "xmlAddRef: Reference list creation failed!\n",
3009 NULL);
Daniel Veillardf6cf57a2007-05-09 23:53:30 +00003010 goto failed;
Daniel Veillard37721922001-05-04 15:21:12 +00003011 }
3012 if (xmlHashAddEntry(table, value, ref_list) < 0) {
3013 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00003014 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3015 "xmlAddRef: Reference list insertion failed!\n",
3016 NULL);
Daniel Veillardf6cf57a2007-05-09 23:53:30 +00003017 goto failed;
Daniel Veillard37721922001-05-04 15:21:12 +00003018 }
3019 }
Daniel Veillardf6cf57a2007-05-09 23:53:30 +00003020 if (xmlListAppend(ref_list, ret) != 0) {
3021 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3022 "xmlAddRef: Reference list insertion failed!\n",
3023 NULL);
3024 goto failed;
3025 }
Daniel Veillard37721922001-05-04 15:21:12 +00003026 return(ret);
Daniel Veillardf6cf57a2007-05-09 23:53:30 +00003027failed:
3028 if (ret != NULL) {
3029 if (ret->value != NULL)
3030 xmlFree((char *)ret->value);
3031 if (ret->name != NULL)
3032 xmlFree((char *)ret->name);
3033 xmlFree(ret);
3034 }
3035 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003036}
3037
3038/**
3039 * xmlFreeRefTable:
3040 * @table: An ref table
3041 *
3042 * Deallocate the memory used by an Ref hash table.
3043 */
3044void
3045xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00003046 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00003047}
3048
3049/**
3050 * xmlIsRef:
3051 * @doc: the document
3052 * @elem: the element carrying the attribute
3053 * @attr: the attribute
3054 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003055 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00003056 * then this is simple, otherwise we use an heuristic: name Ref (upper
3057 * or lowercase).
3058 *
3059 * Returns 0 or 1 depending on the lookup result
3060 */
3061int
3062xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003063 if (attr == NULL)
3064 return(0);
3065 if (doc == NULL) {
3066 doc = attr->doc;
3067 if (doc == NULL) return(0);
3068 }
3069
Daniel Veillard37721922001-05-04 15:21:12 +00003070 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3071 return(0);
3072 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3073 /* TODO @@@ */
3074 return(0);
3075 } else {
3076 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00003077
Daniel Veillardce244ad2004-11-05 10:03:46 +00003078 if (elem == NULL) return(0);
Daniel Veillard37721922001-05-04 15:21:12 +00003079 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3080 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3081 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3082 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00003083
Daniel Veillard37721922001-05-04 15:21:12 +00003084 if ((attrDecl != NULL) &&
3085 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3086 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3087 return(1);
3088 }
3089 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003090}
3091
3092/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003093 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00003094 * @doc: the document
3095 * @attr: the attribute
3096 *
3097 * Remove the given attribute from the Ref table maintained internally.
3098 *
3099 * Returns -1 if the lookup failed and 0 otherwise
3100 */
3101int
3102xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00003103 xmlListPtr ref_list;
3104 xmlRefTablePtr table;
3105 xmlChar *ID;
3106 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00003107
Daniel Veillard37721922001-05-04 15:21:12 +00003108 if (doc == NULL) return(-1);
3109 if (attr == NULL) return(-1);
3110 table = (xmlRefTablePtr) doc->refs;
3111 if (table == NULL)
3112 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003113
Daniel Veillard37721922001-05-04 15:21:12 +00003114 if (attr == NULL)
3115 return(-1);
3116 ID = xmlNodeListGetString(doc, attr->children, 1);
3117 if (ID == NULL)
3118 return(-1);
3119 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00003120
Daniel Veillard37721922001-05-04 15:21:12 +00003121 if(ref_list == NULL) {
3122 xmlFree(ID);
3123 return (-1);
3124 }
3125 /* At this point, ref_list refers to a list of references which
3126 * have the same key as the supplied attr. Our list of references
3127 * is ordered by reference address and we don't have that information
3128 * here to use when removing. We'll have to walk the list and
3129 * check for a matching attribute, when we find one stop the walk
3130 * and remove the entry.
3131 * The list is ordered by reference, so that means we don't have the
3132 * key. Passing the list and the reference to the walker means we
3133 * will have enough data to be able to remove the entry.
3134 */
3135 target.l = ref_list;
3136 target.ap = attr;
3137
3138 /* Remove the supplied attr from our list */
3139 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00003140
Daniel Veillard37721922001-05-04 15:21:12 +00003141 /*If the list is empty then remove the list entry in the hash */
3142 if (xmlListEmpty(ref_list))
3143 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
3144 xmlFreeRefList);
3145 xmlFree(ID);
3146 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003147}
3148
3149/**
3150 * xmlGetRefs:
3151 * @doc: pointer to the document
3152 * @ID: the ID value
3153 *
3154 * Find the set of references for the supplied ID.
3155 *
3156 * Returns NULL if not found, otherwise node set for the ID.
3157 */
3158xmlListPtr
3159xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00003160 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00003161
Daniel Veillard37721922001-05-04 15:21:12 +00003162 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003163 return(NULL);
3164 }
Owen Taylor3473f882001-02-23 17:55:21 +00003165
Daniel Veillard37721922001-05-04 15:21:12 +00003166 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003167 return(NULL);
3168 }
Owen Taylor3473f882001-02-23 17:55:21 +00003169
Daniel Veillard37721922001-05-04 15:21:12 +00003170 table = (xmlRefTablePtr) doc->refs;
3171 if (table == NULL)
3172 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003173
Daniel Veillard37721922001-05-04 15:21:12 +00003174 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00003175}
3176
3177/************************************************************************
3178 * *
3179 * Routines for validity checking *
3180 * *
3181 ************************************************************************/
3182
3183/**
3184 * xmlGetDtdElementDesc:
3185 * @dtd: a pointer to the DtD to search
3186 * @name: the element name
3187 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003188 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003189 *
3190 * returns the xmlElementPtr if found or NULL
3191 */
3192
3193xmlElementPtr
3194xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3195 xmlElementTablePtr table;
3196 xmlElementPtr cur;
3197 xmlChar *uqname = NULL, *prefix = NULL;
3198
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00003199 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003200 if (dtd->elements == NULL)
3201 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003202 table = (xmlElementTablePtr) dtd->elements;
3203
3204 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003205 if (uqname != NULL)
3206 name = uqname;
3207 cur = xmlHashLookup2(table, name, prefix);
3208 if (prefix != NULL) xmlFree(prefix);
3209 if (uqname != NULL) xmlFree(uqname);
3210 return(cur);
3211}
3212/**
3213 * xmlGetDtdElementDesc2:
3214 * @dtd: a pointer to the DtD to search
3215 * @name: the element name
3216 * @create: create an empty description if not found
3217 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003218 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00003219 *
3220 * returns the xmlElementPtr if found or NULL
3221 */
3222
Daniel Veillard86fd5a72001-12-13 14:55:21 +00003223static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00003224xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3225 xmlElementTablePtr table;
3226 xmlElementPtr cur;
3227 xmlChar *uqname = NULL, *prefix = NULL;
3228
3229 if (dtd == NULL) return(NULL);
3230 if (dtd->elements == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003231 xmlDictPtr dict = NULL;
3232
3233 if (dtd->doc != NULL)
3234 dict = dtd->doc->dict;
3235
Daniel Veillarda10efa82001-04-18 13:09:01 +00003236 if (!create)
3237 return(NULL);
3238 /*
3239 * Create the Element table if needed.
3240 */
3241 table = (xmlElementTablePtr) dtd->elements;
3242 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003243 table = xmlHashCreateDict(0, dict);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003244 dtd->elements = (void *) table;
3245 }
3246 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003247 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003248 return(NULL);
3249 }
3250 }
3251 table = (xmlElementTablePtr) dtd->elements;
3252
3253 uqname = xmlSplitQName2(name, &prefix);
3254 if (uqname != NULL)
3255 name = uqname;
3256 cur = xmlHashLookup2(table, name, prefix);
3257 if ((cur == NULL) && (create)) {
3258 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3259 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003260 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003261 return(NULL);
3262 }
3263 memset(cur, 0, sizeof(xmlElement));
3264 cur->type = XML_ELEMENT_DECL;
3265
3266 /*
3267 * fill the structure.
3268 */
3269 cur->name = xmlStrdup(name);
3270 cur->prefix = xmlStrdup(prefix);
3271 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3272
3273 xmlHashAddEntry2(table, name, prefix, cur);
3274 }
3275 if (prefix != NULL) xmlFree(prefix);
3276 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003277 return(cur);
3278}
3279
3280/**
3281 * xmlGetDtdQElementDesc:
3282 * @dtd: a pointer to the DtD to search
3283 * @name: the element name
3284 * @prefix: the element namespace prefix
3285 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003286 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003287 *
3288 * returns the xmlElementPtr if found or NULL
3289 */
3290
Daniel Veillard48da9102001-08-07 01:10:10 +00003291xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003292xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3293 const xmlChar *prefix) {
3294 xmlElementTablePtr table;
3295
3296 if (dtd == NULL) return(NULL);
3297 if (dtd->elements == NULL) return(NULL);
3298 table = (xmlElementTablePtr) dtd->elements;
3299
3300 return(xmlHashLookup2(table, name, prefix));
3301}
3302
3303/**
3304 * xmlGetDtdAttrDesc:
3305 * @dtd: a pointer to the DtD to search
3306 * @elem: the element name
3307 * @name: the attribute name
3308 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003309 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003310 * this element.
3311 *
3312 * returns the xmlAttributePtr if found or NULL
3313 */
3314
3315xmlAttributePtr
3316xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3317 xmlAttributeTablePtr table;
3318 xmlAttributePtr cur;
3319 xmlChar *uqname = NULL, *prefix = NULL;
3320
3321 if (dtd == NULL) return(NULL);
3322 if (dtd->attributes == NULL) return(NULL);
3323
3324 table = (xmlAttributeTablePtr) dtd->attributes;
3325 if (table == NULL)
3326 return(NULL);
3327
3328 uqname = xmlSplitQName2(name, &prefix);
3329
3330 if (uqname != NULL) {
3331 cur = xmlHashLookup3(table, uqname, prefix, elem);
3332 if (prefix != NULL) xmlFree(prefix);
3333 if (uqname != NULL) xmlFree(uqname);
3334 } else
3335 cur = xmlHashLookup3(table, name, NULL, elem);
3336 return(cur);
3337}
3338
3339/**
3340 * xmlGetDtdQAttrDesc:
3341 * @dtd: a pointer to the DtD to search
3342 * @elem: the element name
3343 * @name: the attribute name
3344 * @prefix: the attribute namespace prefix
3345 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003346 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003347 * this element.
3348 *
3349 * returns the xmlAttributePtr if found or NULL
3350 */
3351
Daniel Veillard48da9102001-08-07 01:10:10 +00003352xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003353xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3354 const xmlChar *prefix) {
3355 xmlAttributeTablePtr table;
3356
3357 if (dtd == NULL) return(NULL);
3358 if (dtd->attributes == NULL) return(NULL);
3359 table = (xmlAttributeTablePtr) dtd->attributes;
3360
3361 return(xmlHashLookup3(table, name, prefix, elem));
3362}
3363
3364/**
3365 * xmlGetDtdNotationDesc:
3366 * @dtd: a pointer to the DtD to search
3367 * @name: the notation name
3368 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003369 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003370 *
3371 * returns the xmlNotationPtr if found or NULL
3372 */
3373
3374xmlNotationPtr
3375xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3376 xmlNotationTablePtr table;
3377
3378 if (dtd == NULL) return(NULL);
3379 if (dtd->notations == NULL) return(NULL);
3380 table = (xmlNotationTablePtr) dtd->notations;
3381
3382 return(xmlHashLookup(table, name));
3383}
3384
Daniel Veillardf54cd532004-02-25 11:52:31 +00003385#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003386/**
3387 * xmlValidateNotationUse:
3388 * @ctxt: the validation context
3389 * @doc: the document
3390 * @notationName: the notation name to check
3391 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003392 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003393 * - [ VC: Notation Declared ]
3394 *
3395 * returns 1 if valid or 0 otherwise
3396 */
3397
3398int
3399xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3400 const xmlChar *notationName) {
3401 xmlNotationPtr notaDecl;
3402 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3403
3404 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3405 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3406 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3407
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003408 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003409 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3410 "NOTATION %s is not declared\n",
3411 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003412 return(0);
3413 }
3414 return(1);
3415}
Daniel Veillardf54cd532004-02-25 11:52:31 +00003416#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003417
3418/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003419 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003420 * @doc: the document
3421 * @name: the element name
3422 *
3423 * Search in the DtDs whether an element accept Mixed content (or ANY)
3424 * basically if it is supposed to accept text childs
3425 *
3426 * returns 0 if no, 1 if yes, and -1 if no element description is available
3427 */
3428
3429int
3430xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3431 xmlElementPtr elemDecl;
3432
3433 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3434
3435 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3436 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3437 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3438 if (elemDecl == NULL) return(-1);
3439 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003440 case XML_ELEMENT_TYPE_UNDEFINED:
3441 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003442 case XML_ELEMENT_TYPE_ELEMENT:
3443 return(0);
3444 case XML_ELEMENT_TYPE_EMPTY:
3445 /*
3446 * return 1 for EMPTY since we want VC error to pop up
3447 * on <empty> </empty> for example
3448 */
3449 case XML_ELEMENT_TYPE_ANY:
3450 case XML_ELEMENT_TYPE_MIXED:
3451 return(1);
3452 }
3453 return(1);
3454}
3455
Daniel Veillard4432df22003-09-28 18:58:27 +00003456#ifdef LIBXML_VALID_ENABLED
Daniel Veillardae0765b2008-07-31 19:54:59 +00003457
3458static int
3459xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3460 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3461 /*
3462 * Use the new checks of production [4] [4a] amd [5] of the
3463 * Update 5 of XML-1.0
3464 */
3465 if (((c >= 'a') && (c <= 'z')) ||
3466 ((c >= 'A') && (c <= 'Z')) ||
3467 (c == '_') || (c == ':') ||
3468 ((c >= 0xC0) && (c <= 0xD6)) ||
3469 ((c >= 0xD8) && (c <= 0xF6)) ||
3470 ((c >= 0xF8) && (c <= 0x2FF)) ||
3471 ((c >= 0x370) && (c <= 0x37D)) ||
3472 ((c >= 0x37F) && (c <= 0x1FFF)) ||
3473 ((c >= 0x200C) && (c <= 0x200D)) ||
3474 ((c >= 0x2070) && (c <= 0x218F)) ||
3475 ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3476 ((c >= 0x3001) && (c <= 0xD7FF)) ||
3477 ((c >= 0xF900) && (c <= 0xFDCF)) ||
3478 ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3479 ((c >= 0x10000) && (c <= 0xEFFFF)))
3480 return(1);
3481 } else {
3482 if (IS_LETTER(c) || (c == '_') || (c == ':'))
3483 return(1);
3484 }
3485 return(0);
3486}
3487
3488static int
3489xmlIsDocNameChar(xmlDocPtr doc, int c) {
3490 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3491 /*
3492 * Use the new checks of production [4] [4a] amd [5] of the
3493 * Update 5 of XML-1.0
3494 */
3495 if (((c >= 'a') && (c <= 'z')) ||
3496 ((c >= 'A') && (c <= 'Z')) ||
3497 ((c >= '0') && (c <= '9')) || /* !start */
3498 (c == '_') || (c == ':') ||
3499 (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3500 ((c >= 0xC0) && (c <= 0xD6)) ||
3501 ((c >= 0xD8) && (c <= 0xF6)) ||
3502 ((c >= 0xF8) && (c <= 0x2FF)) ||
3503 ((c >= 0x300) && (c <= 0x36F)) || /* !start */
3504 ((c >= 0x370) && (c <= 0x37D)) ||
3505 ((c >= 0x37F) && (c <= 0x1FFF)) ||
3506 ((c >= 0x200C) && (c <= 0x200D)) ||
3507 ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3508 ((c >= 0x2070) && (c <= 0x218F)) ||
3509 ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3510 ((c >= 0x3001) && (c <= 0xD7FF)) ||
3511 ((c >= 0xF900) && (c <= 0xFDCF)) ||
3512 ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3513 ((c >= 0x10000) && (c <= 0xEFFFF)))
3514 return(1);
3515 } else {
3516 if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3517 (c == '.') || (c == '-') ||
3518 (c == '_') || (c == ':') ||
3519 (IS_COMBINING(c)) ||
3520 (IS_EXTENDER(c)))
3521 return(1);
3522 }
3523 return(0);
3524}
3525
3526/**
3527 * xmlValidateNameValue:
3528 * @doc: pointer to the document or NULL
3529 * @value: an Name value
3530 *
3531 * Validate that the given value match Name production
3532 *
3533 * returns 1 if valid or 0 otherwise
3534 */
3535
3536static int
3537xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3538 const xmlChar *cur;
3539 int val, len;
3540
3541 if (value == NULL) return(0);
3542 cur = value;
3543 val = xmlStringCurrentChar(NULL, cur, &len);
3544 cur += len;
3545 if (!xmlIsDocNameStartChar(doc, val))
3546 return(0);
3547
3548 val = xmlStringCurrentChar(NULL, cur, &len);
3549 cur += len;
3550 while (xmlIsDocNameChar(doc, val)) {
3551 val = xmlStringCurrentChar(NULL, cur, &len);
3552 cur += len;
3553 }
3554
3555 if (val != 0) return(0);
3556
3557 return(1);
3558}
3559
Owen Taylor3473f882001-02-23 17:55:21 +00003560/**
3561 * xmlValidateNameValue:
3562 * @value: an Name value
3563 *
3564 * Validate that the given value match Name production
3565 *
3566 * returns 1 if valid or 0 otherwise
3567 */
3568
Daniel Veillard9b731d72002-04-14 12:56:08 +00003569int
Owen Taylor3473f882001-02-23 17:55:21 +00003570xmlValidateNameValue(const xmlChar *value) {
Daniel Veillardae0765b2008-07-31 19:54:59 +00003571 return(xmlValidateNameValueInternal(NULL, value));
3572}
3573
3574/**
3575 * xmlValidateNamesValueInternal:
3576 * @doc: pointer to the document or NULL
3577 * @value: an Names value
3578 *
3579 * Validate that the given value match Names production
3580 *
3581 * returns 1 if valid or 0 otherwise
3582 */
3583
3584static int
3585xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00003586 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003587 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003588
3589 if (value == NULL) return(0);
3590 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003591 val = xmlStringCurrentChar(NULL, cur, &len);
3592 cur += len;
Daniel Veillardae0765b2008-07-31 19:54:59 +00003593
3594 if (!xmlIsDocNameStartChar(doc, val))
Owen Taylor3473f882001-02-23 17:55:21 +00003595 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003596
Daniel Veillardd8224e02002-01-13 15:43:22 +00003597 val = xmlStringCurrentChar(NULL, cur, &len);
3598 cur += len;
Daniel Veillardae0765b2008-07-31 19:54:59 +00003599 while (xmlIsDocNameChar(doc, val)) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003600 val = xmlStringCurrentChar(NULL, cur, &len);
3601 cur += len;
3602 }
Owen Taylor3473f882001-02-23 17:55:21 +00003603
Daniel Veillardae0765b2008-07-31 19:54:59 +00003604 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3605 while (val == 0x20) {
3606 while (val == 0x20) {
3607 val = xmlStringCurrentChar(NULL, cur, &len);
3608 cur += len;
3609 }
3610
3611 if (!xmlIsDocNameStartChar(doc, val))
3612 return(0);
3613
3614 val = xmlStringCurrentChar(NULL, cur, &len);
3615 cur += len;
3616
3617 while (xmlIsDocNameChar(doc, val)) {
3618 val = xmlStringCurrentChar(NULL, cur, &len);
3619 cur += len;
3620 }
3621 }
3622
Daniel Veillardd8224e02002-01-13 15:43:22 +00003623 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003624
3625 return(1);
3626}
3627
3628/**
3629 * xmlValidateNamesValue:
3630 * @value: an Names value
3631 *
3632 * Validate that the given value match Names production
3633 *
3634 * returns 1 if valid or 0 otherwise
3635 */
3636
Daniel Veillard9b731d72002-04-14 12:56:08 +00003637int
Owen Taylor3473f882001-02-23 17:55:21 +00003638xmlValidateNamesValue(const xmlChar *value) {
Daniel Veillardae0765b2008-07-31 19:54:59 +00003639 return(xmlValidateNamesValueInternal(NULL, value));
3640}
3641
3642/**
3643 * xmlValidateNmtokenValueInternal:
3644 * @doc: pointer to the document or NULL
3645 * @value: an Nmtoken value
3646 *
3647 * Validate that the given value match Nmtoken production
3648 *
3649 * [ VC: Name Token ]
3650 *
3651 * returns 1 if valid or 0 otherwise
3652 */
3653
3654static int
3655xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00003656 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003657 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003658
3659 if (value == NULL) return(0);
3660 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003661 val = xmlStringCurrentChar(NULL, cur, &len);
3662 cur += len;
Daniel Veillardae0765b2008-07-31 19:54:59 +00003663
3664 if (!xmlIsDocNameChar(doc, val))
Owen Taylor3473f882001-02-23 17:55:21 +00003665 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003666
Daniel Veillardd8224e02002-01-13 15:43:22 +00003667 val = xmlStringCurrentChar(NULL, cur, &len);
3668 cur += len;
Daniel Veillardae0765b2008-07-31 19:54:59 +00003669 while (xmlIsDocNameChar(doc, val)) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003670 val = xmlStringCurrentChar(NULL, cur, &len);
3671 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003672 }
3673
Daniel Veillardd8224e02002-01-13 15:43:22 +00003674 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003675
3676 return(1);
3677}
3678
3679/**
3680 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003681 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003682 *
3683 * Validate that the given value match Nmtoken production
3684 *
3685 * [ VC: Name Token ]
Daniel Veillardae0765b2008-07-31 19:54:59 +00003686 *
Owen Taylor3473f882001-02-23 17:55:21 +00003687 * returns 1 if valid or 0 otherwise
3688 */
3689
Daniel Veillard9b731d72002-04-14 12:56:08 +00003690int
Owen Taylor3473f882001-02-23 17:55:21 +00003691xmlValidateNmtokenValue(const xmlChar *value) {
Daniel Veillardae0765b2008-07-31 19:54:59 +00003692 return(xmlValidateNmtokenValueInternal(NULL, value));
3693}
3694
3695/**
3696 * xmlValidateNmtokensValueInternal:
3697 * @doc: pointer to the document or NULL
3698 * @value: an Nmtokens value
3699 *
3700 * Validate that the given value match Nmtokens production
3701 *
3702 * [ VC: Name Token ]
3703 *
3704 * returns 1 if valid or 0 otherwise
3705 */
3706
3707static int
3708xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00003709 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003710 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003711
3712 if (value == NULL) return(0);
3713 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003714 val = xmlStringCurrentChar(NULL, cur, &len);
3715 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003716
Daniel Veillardae0765b2008-07-31 19:54:59 +00003717 while (IS_BLANK(val)) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003718 val = xmlStringCurrentChar(NULL, cur, &len);
3719 cur += len;
3720 }
Owen Taylor3473f882001-02-23 17:55:21 +00003721
Daniel Veillardae0765b2008-07-31 19:54:59 +00003722 if (!xmlIsDocNameChar(doc, val))
3723 return(0);
3724
3725 while (xmlIsDocNameChar(doc, val)) {
3726 val = xmlStringCurrentChar(NULL, cur, &len);
3727 cur += len;
3728 }
3729
3730 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3731 while (val == 0x20) {
3732 while (val == 0x20) {
3733 val = xmlStringCurrentChar(NULL, cur, &len);
3734 cur += len;
3735 }
3736 if (val == 0) return(1);
3737
3738 if (!xmlIsDocNameChar(doc, val))
3739 return(0);
3740
3741 val = xmlStringCurrentChar(NULL, cur, &len);
3742 cur += len;
3743
3744 while (xmlIsDocNameChar(doc, val)) {
3745 val = xmlStringCurrentChar(NULL, cur, &len);
3746 cur += len;
3747 }
3748 }
3749
Daniel Veillardd8224e02002-01-13 15:43:22 +00003750 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003751
3752 return(1);
3753}
3754
3755/**
3756 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003757 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003758 *
3759 * Validate that the given value match Nmtokens production
3760 *
3761 * [ VC: Name Token ]
Daniel Veillardae0765b2008-07-31 19:54:59 +00003762 *
Owen Taylor3473f882001-02-23 17:55:21 +00003763 * returns 1 if valid or 0 otherwise
3764 */
3765
Daniel Veillard9b731d72002-04-14 12:56:08 +00003766int
Owen Taylor3473f882001-02-23 17:55:21 +00003767xmlValidateNmtokensValue(const xmlChar *value) {
Daniel Veillardae0765b2008-07-31 19:54:59 +00003768 return(xmlValidateNmtokensValueInternal(NULL, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003769}
3770
3771/**
3772 * xmlValidateNotationDecl:
3773 * @ctxt: the validation context
3774 * @doc: a document instance
3775 * @nota: a notation definition
3776 *
3777 * Try to validate a single notation definition
3778 * basically it does the following checks as described by the
3779 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003780 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003781 * But this function get called anyway ...
3782 *
3783 * returns 1 if valid or 0 otherwise
3784 */
3785
3786int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003787xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3788 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003789 int ret = 1;
3790
3791 return(ret);
3792}
3793
3794/**
Daniel Veillardbe2bd6a2008-11-27 15:26:28 +00003795 * xmlValidateAttributeValueInternal:
3796 * @doc: the document
Owen Taylor3473f882001-02-23 17:55:21 +00003797 * @type: an attribute type
3798 * @value: an attribute value
3799 *
3800 * Validate that the given attribute value match the proper production
3801 *
Owen Taylor3473f882001-02-23 17:55:21 +00003802 * returns 1 if valid or 0 otherwise
3803 */
3804
Daniel Veillardae0765b2008-07-31 19:54:59 +00003805static int
3806xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
3807 const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00003808 switch (type) {
3809 case XML_ATTRIBUTE_ENTITIES:
3810 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardae0765b2008-07-31 19:54:59 +00003811 return(xmlValidateNamesValueInternal(doc, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003812 case XML_ATTRIBUTE_ENTITY:
3813 case XML_ATTRIBUTE_IDREF:
3814 case XML_ATTRIBUTE_ID:
3815 case XML_ATTRIBUTE_NOTATION:
Daniel Veillardae0765b2008-07-31 19:54:59 +00003816 return(xmlValidateNameValueInternal(doc, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003817 case XML_ATTRIBUTE_NMTOKENS:
3818 case XML_ATTRIBUTE_ENUMERATION:
Daniel Veillardae0765b2008-07-31 19:54:59 +00003819 return(xmlValidateNmtokensValueInternal(doc, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003820 case XML_ATTRIBUTE_NMTOKEN:
Daniel Veillardae0765b2008-07-31 19:54:59 +00003821 return(xmlValidateNmtokenValueInternal(doc, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003822 case XML_ATTRIBUTE_CDATA:
3823 break;
3824 }
3825 return(1);
3826}
3827
Daniel Veillardbe2bd6a2008-11-27 15:26:28 +00003828/**
3829 * xmlValidateAttributeValue:
3830 * @type: an attribute type
3831 * @value: an attribute value
3832 *
3833 * Validate that the given attribute value match the proper production
3834 *
3835 * [ VC: ID ]
3836 * Values of type ID must match the Name production....
3837 *
3838 * [ VC: IDREF ]
3839 * Values of type IDREF must match the Name production, and values
3840 * of type IDREFS must match Names ...
3841 *
3842 * [ VC: Entity Name ]
3843 * Values of type ENTITY must match the Name production, values
3844 * of type ENTITIES must match Names ...
3845 *
3846 * [ VC: Name Token ]
3847 * Values of type NMTOKEN must match the Nmtoken production; values
3848 * of type NMTOKENS must match Nmtokens.
3849 *
3850 * returns 1 if valid or 0 otherwise
3851 */
Daniel Veillardae0765b2008-07-31 19:54:59 +00003852int
3853xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3854 return(xmlValidateAttributeValueInternal(NULL, type, value));
3855}
3856
Owen Taylor3473f882001-02-23 17:55:21 +00003857/**
3858 * xmlValidateAttributeValue2:
3859 * @ctxt: the validation context
3860 * @doc: the document
3861 * @name: the attribute name (used for error reporting only)
3862 * @type: the attribute type
3863 * @value: the attribute value
3864 *
3865 * Validate that the given attribute value match a given type.
3866 * This typically cannot be done before having finished parsing
3867 * the subsets.
3868 *
3869 * [ VC: IDREF ]
3870 * Values of type IDREF must match one of the declared IDs
3871 * Values of type IDREFS must match a sequence of the declared IDs
3872 * each Name must match the value of an ID attribute on some element
3873 * in the XML document; i.e. IDREF values must match the value of
3874 * some ID attribute
3875 *
3876 * [ VC: Entity Name ]
3877 * Values of type ENTITY must match one declared entity
3878 * Values of type ENTITIES must match a sequence of declared entities
3879 *
3880 * [ VC: Notation Attributes ]
3881 * all notation names in the declaration must be declared.
3882 *
3883 * returns 1 if valid or 0 otherwise
3884 */
3885
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003886static int
Owen Taylor3473f882001-02-23 17:55:21 +00003887xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3888 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3889 int ret = 1;
3890 switch (type) {
3891 case XML_ATTRIBUTE_IDREFS:
3892 case XML_ATTRIBUTE_IDREF:
3893 case XML_ATTRIBUTE_ID:
3894 case XML_ATTRIBUTE_NMTOKENS:
3895 case XML_ATTRIBUTE_ENUMERATION:
3896 case XML_ATTRIBUTE_NMTOKEN:
3897 case XML_ATTRIBUTE_CDATA:
3898 break;
3899 case XML_ATTRIBUTE_ENTITY: {
3900 xmlEntityPtr ent;
3901
3902 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003903 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003904 if ((ent == NULL) && (doc->standalone == 1)) {
3905 doc->standalone = 0;
3906 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003907 }
Owen Taylor3473f882001-02-23 17:55:21 +00003908 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003909 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3910 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003911 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003912 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003913 ret = 0;
3914 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003915 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3916 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003917 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003918 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003919 ret = 0;
3920 }
3921 break;
3922 }
3923 case XML_ATTRIBUTE_ENTITIES: {
3924 xmlChar *dup, *nam = NULL, *cur, save;
3925 xmlEntityPtr ent;
3926
3927 dup = xmlStrdup(value);
3928 if (dup == NULL)
3929 return(0);
3930 cur = dup;
3931 while (*cur != 0) {
3932 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003933 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003934 save = *cur;
3935 *cur = 0;
3936 ent = xmlGetDocEntity(doc, nam);
3937 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003938 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3939 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003940 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003941 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003942 ret = 0;
3943 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003944 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3945 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003946 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003947 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003948 ret = 0;
3949 }
3950 if (save == 0)
3951 break;
3952 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003953 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003954 }
3955 xmlFree(dup);
3956 break;
3957 }
3958 case XML_ATTRIBUTE_NOTATION: {
3959 xmlNotationPtr nota;
3960
3961 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3962 if ((nota == NULL) && (doc->extSubset != NULL))
3963 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3964
3965 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003966 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3967 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003968 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003969 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003970 ret = 0;
3971 }
3972 break;
3973 }
3974 }
3975 return(ret);
3976}
3977
3978/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003979 * xmlValidCtxtNormalizeAttributeValue:
3980 * @ctxt: the validation context
3981 * @doc: the document
3982 * @elem: the parent
3983 * @name: the attribute name
3984 * @value: the attribute value
3985 * @ctxt: the validation context or NULL
3986 *
3987 * Does the validation related extra step of the normalization of attribute
3988 * values:
3989 *
3990 * If the declared value is not CDATA, then the XML processor must further
3991 * process the normalized attribute value by discarding any leading and
3992 * trailing space (#x20) characters, and by replacing sequences of space
3993 * (#x20) characters by single space (#x20) character.
3994 *
3995 * Also check VC: Standalone Document Declaration in P32, and update
3996 * ctxt->valid accordingly
3997 *
3998 * returns a new normalized string if normalization is needed, NULL otherwise
3999 * the caller must free the returned value.
4000 */
4001
4002xmlChar *
4003xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4004 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
4005 xmlChar *ret, *dst;
4006 const xmlChar *src;
4007 xmlAttributePtr attrDecl = NULL;
4008 int extsubset = 0;
4009
4010 if (doc == NULL) return(NULL);
4011 if (elem == NULL) return(NULL);
4012 if (name == NULL) return(NULL);
4013 if (value == NULL) return(NULL);
4014
4015 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004016 xmlChar fn[50];
4017 xmlChar *fullname;
4018
4019 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4020 if (fullname == NULL)
Daniel Veillard24505b02005-07-28 23:49:35 +00004021 return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00004022 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00004023 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004024 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00004025 if (attrDecl != NULL)
4026 extsubset = 1;
4027 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004028 if ((fullname != fn) && (fullname != elem->name))
4029 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00004030 }
4031 if ((attrDecl == NULL) && (doc->intSubset != NULL))
4032 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4033 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4034 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4035 if (attrDecl != NULL)
4036 extsubset = 1;
4037 }
4038
4039 if (attrDecl == NULL)
4040 return(NULL);
4041 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4042 return(NULL);
4043
4044 ret = xmlStrdup(value);
4045 if (ret == NULL)
4046 return(NULL);
4047 src = value;
4048 dst = ret;
4049 while (*src == 0x20) src++;
4050 while (*src != 0) {
4051 if (*src == 0x20) {
4052 while (*src == 0x20) src++;
4053 if (*src != 0)
4054 *dst++ = 0x20;
4055 } else {
4056 *dst++ = *src++;
4057 }
4058 }
4059 *dst = 0;
4060 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004061 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00004062"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004063 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00004064 ctxt->valid = 0;
4065 }
4066 return(ret);
4067}
4068
4069/**
Owen Taylor3473f882001-02-23 17:55:21 +00004070 * xmlValidNormalizeAttributeValue:
4071 * @doc: the document
4072 * @elem: the parent
4073 * @name: the attribute name
4074 * @value: the attribute value
4075 *
4076 * Does the validation related extra step of the normalization of attribute
4077 * values:
4078 *
4079 * If the declared value is not CDATA, then the XML processor must further
4080 * process the normalized attribute value by discarding any leading and
4081 * trailing space (#x20) characters, and by replacing sequences of space
4082 * (#x20) characters by single space (#x20) character.
4083 *
Daniel Veillard652327a2003-09-29 18:02:38 +00004084 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00004085 * the caller must free the returned value.
4086 */
4087
4088xmlChar *
4089xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
4090 const xmlChar *name, const xmlChar *value) {
4091 xmlChar *ret, *dst;
4092 const xmlChar *src;
4093 xmlAttributePtr attrDecl = NULL;
4094
4095 if (doc == NULL) return(NULL);
4096 if (elem == NULL) return(NULL);
4097 if (name == NULL) return(NULL);
4098 if (value == NULL) return(NULL);
4099
4100 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004101 xmlChar fn[50];
4102 xmlChar *fullname;
4103
4104 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4105 if (fullname == NULL)
Daniel Veillard24505b02005-07-28 23:49:35 +00004106 return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00004107 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00004108 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004109 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
4110 if ((fullname != fn) && (fullname != elem->name))
4111 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004112 }
4113 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4114 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4115 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4116
4117 if (attrDecl == NULL)
4118 return(NULL);
4119 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4120 return(NULL);
4121
4122 ret = xmlStrdup(value);
4123 if (ret == NULL)
4124 return(NULL);
4125 src = value;
4126 dst = ret;
4127 while (*src == 0x20) src++;
4128 while (*src != 0) {
4129 if (*src == 0x20) {
4130 while (*src == 0x20) src++;
4131 if (*src != 0)
4132 *dst++ = 0x20;
4133 } else {
4134 *dst++ = *src++;
4135 }
4136 }
4137 *dst = 0;
4138 return(ret);
4139}
4140
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004141static void
Owen Taylor3473f882001-02-23 17:55:21 +00004142xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00004143 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00004144 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4145}
4146
4147/**
4148 * xmlValidateAttributeDecl:
4149 * @ctxt: the validation context
4150 * @doc: a document instance
4151 * @attr: an attribute definition
4152 *
4153 * Try to validate a single attribute definition
4154 * basically it does the following checks as described by the
4155 * XML-1.0 recommendation:
4156 * - [ VC: Attribute Default Legal ]
4157 * - [ VC: Enumeration ]
4158 * - [ VC: ID Attribute Default ]
4159 *
4160 * The ID/IDREF uniqueness and matching are done separately
4161 *
4162 * returns 1 if valid or 0 otherwise
4163 */
4164
4165int
4166xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4167 xmlAttributePtr attr) {
4168 int ret = 1;
4169 int val;
4170 CHECK_DTD;
4171 if(attr == NULL) return(1);
Daniel Veillardae0765b2008-07-31 19:54:59 +00004172
Owen Taylor3473f882001-02-23 17:55:21 +00004173 /* Attribute Default Legal */
4174 /* Enumeration */
4175 if (attr->defaultValue != NULL) {
Daniel Veillardae0765b2008-07-31 19:54:59 +00004176 val = xmlValidateAttributeValueInternal(doc, attr->atype,
4177 attr->defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00004178 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004179 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004180 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004181 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004182 }
4183 ret &= val;
4184 }
4185
4186 /* ID Attribute Default */
4187 if ((attr->atype == XML_ATTRIBUTE_ID)&&
4188 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4189 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004190 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004191 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004192 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004193 ret = 0;
4194 }
4195
4196 /* One ID per Element Type */
4197 if (attr->atype == XML_ATTRIBUTE_ID) {
4198 int nbId;
4199
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004200 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00004201 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4202 attr->elem);
4203 if (elem != NULL) {
Daniel Veillarddbee0f12005-06-27 13:42:57 +00004204 nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00004205 } else {
4206 xmlAttributeTablePtr table;
4207
4208 /*
4209 * The attribute may be declared in the internal subset and the
4210 * element in the external subset.
4211 */
4212 nbId = 0;
Daniel Veillard11ce4002006-03-10 00:36:23 +00004213 if (doc->intSubset != NULL) {
4214 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4215 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
4216 xmlValidateAttributeIdCallback, &nbId);
4217 }
Owen Taylor3473f882001-02-23 17:55:21 +00004218 }
4219 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004220
4221 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004222 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4223 attr->elem, nbId, attr->name);
4224 } else if (doc->extSubset != NULL) {
4225 int extId = 0;
4226 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4227 if (elem != NULL) {
Daniel Veillarddbee0f12005-06-27 13:42:57 +00004228 extId = xmlScanIDAttributeDecl(NULL, elem, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00004229 }
4230 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004231 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004232 "Element %s has %d ID attribute defined in the external subset : %s\n",
4233 attr->elem, extId, attr->name);
4234 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004235 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004236"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004237 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004238 }
4239 }
4240 }
4241
4242 /* Validity Constraint: Enumeration */
4243 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4244 xmlEnumerationPtr tree = attr->tree;
4245 while (tree != NULL) {
4246 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4247 tree = tree->next;
4248 }
4249 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004250 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004251"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004252 attr->defaultValue, attr->name, attr->elem);
4253 ret = 0;
4254 }
4255 }
4256
4257 return(ret);
4258}
4259
4260/**
4261 * xmlValidateElementDecl:
4262 * @ctxt: the validation context
4263 * @doc: a document instance
4264 * @elem: an element definition
4265 *
4266 * Try to validate a single element definition
4267 * basically it does the following checks as described by the
4268 * XML-1.0 recommendation:
4269 * - [ VC: One ID per Element Type ]
4270 * - [ VC: No Duplicate Types ]
4271 * - [ VC: Unique Element Type Declaration ]
4272 *
4273 * returns 1 if valid or 0 otherwise
4274 */
4275
4276int
4277xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4278 xmlElementPtr elem) {
4279 int ret = 1;
4280 xmlElementPtr tst;
4281
4282 CHECK_DTD;
4283
4284 if (elem == NULL) return(1);
4285
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004286#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00004287#ifdef LIBXML_REGEXP_ENABLED
4288 /* Build the regexp associated to the content model */
4289 ret = xmlValidBuildContentModel(ctxt, elem);
4290#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004291#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00004292
Owen Taylor3473f882001-02-23 17:55:21 +00004293 /* No Duplicate Types */
4294 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4295 xmlElementContentPtr cur, next;
4296 const xmlChar *name;
4297
4298 cur = elem->content;
4299 while (cur != NULL) {
4300 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4301 if (cur->c1 == NULL) break;
4302 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4303 name = cur->c1->name;
4304 next = cur->c2;
4305 while (next != NULL) {
4306 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00004307 if ((xmlStrEqual(next->name, name)) &&
4308 (xmlStrEqual(next->prefix, cur->prefix))) {
4309 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004310 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00004311 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004312 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004313 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004314 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004315 "Definition of %s has duplicate references of %s:%s\n",
4316 elem->name, cur->prefix, name);
4317 }
Owen Taylor3473f882001-02-23 17:55:21 +00004318 ret = 0;
4319 }
4320 break;
4321 }
4322 if (next->c1 == NULL) break;
4323 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00004324 if ((xmlStrEqual(next->c1->name, name)) &&
4325 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
4326 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004327 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004328 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004329 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004330 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004331 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004332 "Definition of %s has duplicate references to %s:%s\n",
4333 elem->name, cur->prefix, name);
4334 }
Owen Taylor3473f882001-02-23 17:55:21 +00004335 ret = 0;
4336 }
4337 next = next->c2;
4338 }
4339 }
4340 cur = cur->c2;
4341 }
4342 }
4343
4344 /* VC: Unique Element Type Declaration */
4345 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004346 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004347 ((tst->prefix == elem->prefix) ||
4348 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004349 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004350 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4351 "Redefinition of element %s\n",
4352 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004353 ret = 0;
4354 }
4355 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004356 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004357 ((tst->prefix == elem->prefix) ||
4358 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004359 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004360 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4361 "Redefinition of element %s\n",
4362 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004363 ret = 0;
4364 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004365 /* One ID per Element Type
4366 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004367 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4368 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004369 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004370 return(ret);
4371}
4372
4373/**
4374 * xmlValidateOneAttribute:
4375 * @ctxt: the validation context
4376 * @doc: a document instance
4377 * @elem: an element instance
4378 * @attr: an attribute instance
4379 * @value: the attribute value (without entities processing)
4380 *
4381 * Try to validate a single attribute for an element
4382 * basically it does the following checks as described by the
4383 * XML-1.0 recommendation:
4384 * - [ VC: Attribute Value Type ]
4385 * - [ VC: Fixed Attribute Default ]
4386 * - [ VC: Entity Name ]
4387 * - [ VC: Name Token ]
4388 * - [ VC: ID ]
4389 * - [ VC: IDREF ]
4390 * - [ VC: Entity Name ]
4391 * - [ VC: Notation Attributes ]
4392 *
4393 * The ID/IDREF uniqueness and matching are done separately
4394 *
4395 * returns 1 if valid or 0 otherwise
4396 */
4397
4398int
4399xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004400 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4401{
Owen Taylor3473f882001-02-23 17:55:21 +00004402 xmlAttributePtr attrDecl = NULL;
4403 int val;
4404 int ret = 1;
4405
4406 CHECK_DTD;
4407 if ((elem == NULL) || (elem->name == NULL)) return(0);
4408 if ((attr == NULL) || (attr->name == NULL)) return(0);
4409
4410 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004411 xmlChar fn[50];
4412 xmlChar *fullname;
4413
4414 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4415 if (fullname == NULL)
4416 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004417 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004418 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004419 attr->name, attr->ns->prefix);
4420 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004421 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004422 attr->name, attr->ns->prefix);
4423 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004424 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004425 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4426 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004427 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004428 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004429 if ((fullname != fn) && (fullname != elem->name))
4430 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004431 }
4432 if (attrDecl == NULL) {
4433 if (attr->ns != NULL) {
4434 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4435 attr->name, attr->ns->prefix);
4436 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4437 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4438 attr->name, attr->ns->prefix);
4439 } else {
4440 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4441 elem->name, attr->name);
4442 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4443 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4444 elem->name, attr->name);
4445 }
4446 }
4447
4448
4449 /* Validity Constraint: Attribute Value Type */
4450 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004451 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004452 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004453 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004454 return(0);
4455 }
4456 attr->atype = attrDecl->atype;
4457
Daniel Veillardae0765b2008-07-31 19:54:59 +00004458 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
Owen Taylor3473f882001-02-23 17:55:21 +00004459 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004460 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004461 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004462 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004463 ret = 0;
4464 }
4465
4466 /* Validity constraint: Fixed Attribute Default */
4467 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4468 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004469 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004470 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004471 attr->name, elem->name, attrDecl->defaultValue);
4472 ret = 0;
4473 }
4474 }
4475
4476 /* Validity Constraint: ID uniqueness */
4477 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4478 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4479 ret = 0;
4480 }
4481
4482 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4483 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4484 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4485 ret = 0;
4486 }
4487
4488 /* Validity Constraint: Notation Attributes */
4489 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4490 xmlEnumerationPtr tree = attrDecl->tree;
4491 xmlNotationPtr nota;
4492
4493 /* First check that the given NOTATION was declared */
4494 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4495 if (nota == NULL)
4496 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4497
4498 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004499 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004500 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004501 value, attr->name, elem->name);
4502 ret = 0;
4503 }
4504
4505 /* Second, verify that it's among the list */
4506 while (tree != NULL) {
4507 if (xmlStrEqual(tree->name, value)) break;
4508 tree = tree->next;
4509 }
4510 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004511 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004512"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004513 value, attr->name, elem->name);
4514 ret = 0;
4515 }
4516 }
4517
4518 /* Validity Constraint: Enumeration */
4519 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4520 xmlEnumerationPtr tree = attrDecl->tree;
4521 while (tree != NULL) {
4522 if (xmlStrEqual(tree->name, value)) break;
4523 tree = tree->next;
4524 }
4525 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004526 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004527 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004528 value, attr->name, elem->name);
4529 ret = 0;
4530 }
4531 }
4532
4533 /* Fixed Attribute Default */
4534 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4535 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004536 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004537 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004538 attr->name, elem->name, attrDecl->defaultValue);
4539 ret = 0;
4540 }
4541
4542 /* Extra check for the attribute value */
4543 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4544 attrDecl->atype, value);
4545
4546 return(ret);
4547}
4548
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004549/**
4550 * xmlValidateOneNamespace:
4551 * @ctxt: the validation context
4552 * @doc: a document instance
4553 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004554 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004555 * @ns: an namespace declaration instance
4556 * @value: the attribute value (without entities processing)
4557 *
4558 * Try to validate a single namespace declaration for an element
4559 * basically it does the following checks as described by the
4560 * XML-1.0 recommendation:
4561 * - [ VC: Attribute Value Type ]
4562 * - [ VC: Fixed Attribute Default ]
4563 * - [ VC: Entity Name ]
4564 * - [ VC: Name Token ]
4565 * - [ VC: ID ]
4566 * - [ VC: IDREF ]
4567 * - [ VC: Entity Name ]
4568 * - [ VC: Notation Attributes ]
4569 *
4570 * The ID/IDREF uniqueness and matching are done separately
4571 *
4572 * returns 1 if valid or 0 otherwise
4573 */
4574
4575int
4576xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4577xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4578 /* xmlElementPtr elemDecl; */
4579 xmlAttributePtr attrDecl = NULL;
4580 int val;
4581 int ret = 1;
4582
4583 CHECK_DTD;
4584 if ((elem == NULL) || (elem->name == NULL)) return(0);
4585 if ((ns == NULL) || (ns->href == NULL)) return(0);
4586
4587 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004588 xmlChar fn[50];
4589 xmlChar *fullname;
4590
4591 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4592 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004593 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004594 return(0);
4595 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004596 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004597 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004598 ns->prefix, BAD_CAST "xmlns");
4599 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004600 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004601 ns->prefix, BAD_CAST "xmlns");
4602 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004603 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004604 BAD_CAST "xmlns");
4605 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004606 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004607 BAD_CAST "xmlns");
4608 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004609 if ((fullname != fn) && (fullname != elem->name))
4610 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004611 }
4612 if (attrDecl == NULL) {
4613 if (ns->prefix != NULL) {
4614 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4615 ns->prefix, BAD_CAST "xmlns");
4616 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4617 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4618 ns->prefix, BAD_CAST "xmlns");
4619 } else {
4620 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4621 elem->name, BAD_CAST "xmlns");
4622 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4623 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4624 elem->name, BAD_CAST "xmlns");
4625 }
4626 }
4627
4628
4629 /* Validity Constraint: Attribute Value Type */
4630 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004631 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004632 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004633 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004634 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004635 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004636 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004637 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004638 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004639 }
4640 return(0);
4641 }
4642
Daniel Veillardae0765b2008-07-31 19:54:59 +00004643 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004644 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004645 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004646 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004647 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004648 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004649 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004650 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004651 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004652 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004653 }
4654 ret = 0;
4655 }
4656
4657 /* Validity constraint: Fixed Attribute Default */
4658 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4659 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004660 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004661 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004662 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4663 ns->prefix, elem->name, attrDecl->defaultValue);
4664 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004665 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004666 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004667 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004668 }
4669 ret = 0;
4670 }
4671 }
4672
4673 /* Validity Constraint: ID uniqueness */
4674 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4675 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4676 ret = 0;
4677 }
4678
4679 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4680 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4681 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4682 ret = 0;
4683 }
4684
4685 /* Validity Constraint: Notation Attributes */
4686 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4687 xmlEnumerationPtr tree = attrDecl->tree;
4688 xmlNotationPtr nota;
4689
4690 /* First check that the given NOTATION was declared */
4691 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4692 if (nota == NULL)
4693 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4694
4695 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004696 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004697 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004698 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4699 value, ns->prefix, elem->name);
4700 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004701 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004702 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004703 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004704 }
4705 ret = 0;
4706 }
4707
4708 /* Second, verify that it's among the list */
4709 while (tree != NULL) {
4710 if (xmlStrEqual(tree->name, value)) break;
4711 tree = tree->next;
4712 }
4713 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004714 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004715 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004716"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4717 value, ns->prefix, elem->name);
4718 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004719 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004720"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004721 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004722 }
4723 ret = 0;
4724 }
4725 }
4726
4727 /* Validity Constraint: Enumeration */
4728 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4729 xmlEnumerationPtr tree = attrDecl->tree;
4730 while (tree != NULL) {
4731 if (xmlStrEqual(tree->name, value)) break;
4732 tree = tree->next;
4733 }
4734 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004735 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004736 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004737"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4738 value, ns->prefix, elem->name);
4739 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004740 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004741"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004742 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004743 }
4744 ret = 0;
4745 }
4746 }
4747
4748 /* Fixed Attribute Default */
4749 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4750 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004751 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004752 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004753 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4754 ns->prefix, elem->name, attrDecl->defaultValue);
4755 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004756 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004757 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004758 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004759 }
4760 ret = 0;
4761 }
4762
4763 /* Extra check for the attribute value */
4764 if (ns->prefix != NULL) {
4765 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4766 attrDecl->atype, value);
4767 } else {
4768 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4769 attrDecl->atype, value);
4770 }
4771
4772 return(ret);
4773}
4774
Daniel Veillard118aed72002-09-24 14:13:13 +00004775#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004776/**
4777 * xmlValidateSkipIgnorable:
4778 * @ctxt: the validation context
4779 * @child: the child list
4780 *
4781 * Skip ignorable elements w.r.t. the validation process
4782 *
4783 * returns the first element to consider for validation of the content model
4784 */
4785
4786static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004787xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004788 while (child != NULL) {
4789 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004790 /* These things are ignored (skipped) during validation. */
4791 case XML_PI_NODE:
4792 case XML_COMMENT_NODE:
4793 case XML_XINCLUDE_START:
4794 case XML_XINCLUDE_END:
4795 child = child->next;
4796 break;
4797 case XML_TEXT_NODE:
4798 if (xmlIsBlankNode(child))
4799 child = child->next;
4800 else
4801 return(child);
4802 break;
4803 /* keep current node */
4804 default:
4805 return(child);
4806 }
4807 }
4808 return(child);
4809}
4810
4811/**
4812 * xmlValidateElementType:
4813 * @ctxt: the validation context
4814 *
4815 * Try to validate the content model of an element internal function
4816 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004817 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4818 * reference is found and -3 if the validation succeeded but
4819 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004820 */
4821
4822static int
4823xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004824 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004825 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004826
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004827 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004828 if ((NODE == NULL) && (CONT == NULL))
4829 return(1);
4830 if ((NODE == NULL) &&
4831 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4832 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4833 return(1);
4834 }
4835 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004836 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004837 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004838
4839 /*
4840 * We arrive here when more states need to be examined
4841 */
4842cont:
4843
4844 /*
4845 * We just recovered from a rollback generated by a possible
4846 * epsilon transition, go directly to the analysis phase
4847 */
4848 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004849 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004850 DEBUG_VALID_STATE(NODE, CONT)
4851 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004852 goto analyze;
4853 }
4854
4855 DEBUG_VALID_STATE(NODE, CONT)
4856 /*
4857 * we may have to save a backup state here. This is the equivalent
4858 * of handling epsilon transition in NFAs.
4859 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004860 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004861 ((CONT->parent == NULL) ||
4862 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004863 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004864 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004865 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004866 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004867 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4868 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004869 }
4870
4871
4872 /*
4873 * Check first if the content matches
4874 */
4875 switch (CONT->type) {
4876 case XML_ELEMENT_CONTENT_PCDATA:
4877 if (NODE == NULL) {
4878 DEBUG_VALID_MSG("pcdata failed no node");
4879 ret = 0;
4880 break;
4881 }
4882 if (NODE->type == XML_TEXT_NODE) {
4883 DEBUG_VALID_MSG("pcdata found, skip to next");
4884 /*
4885 * go to next element in the content model
4886 * skipping ignorable elems
4887 */
4888 do {
4889 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004890 NODE = xmlValidateSkipIgnorable(NODE);
4891 if ((NODE != NULL) &&
4892 (NODE->type == XML_ENTITY_REF_NODE))
4893 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004894 } while ((NODE != NULL) &&
4895 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004896 (NODE->type != XML_TEXT_NODE) &&
4897 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004898 ret = 1;
4899 break;
4900 } else {
4901 DEBUG_VALID_MSG("pcdata failed");
4902 ret = 0;
4903 break;
4904 }
4905 break;
4906 case XML_ELEMENT_CONTENT_ELEMENT:
4907 if (NODE == NULL) {
4908 DEBUG_VALID_MSG("element failed no node");
4909 ret = 0;
4910 break;
4911 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004912 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4913 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004914 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004915 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4916 ret = (CONT->prefix == NULL);
4917 } else if (CONT->prefix == NULL) {
4918 ret = 0;
4919 } else {
4920 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4921 }
4922 }
4923 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004924 DEBUG_VALID_MSG("element found, skip to next");
4925 /*
4926 * go to next element in the content model
4927 * skipping ignorable elems
4928 */
4929 do {
4930 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004931 NODE = xmlValidateSkipIgnorable(NODE);
4932 if ((NODE != NULL) &&
4933 (NODE->type == XML_ENTITY_REF_NODE))
4934 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004935 } while ((NODE != NULL) &&
4936 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004937 (NODE->type != XML_TEXT_NODE) &&
4938 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004939 } else {
4940 DEBUG_VALID_MSG("element failed");
4941 ret = 0;
4942 break;
4943 }
4944 break;
4945 case XML_ELEMENT_CONTENT_OR:
4946 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004947 * Small optimization.
4948 */
4949 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4950 if ((NODE == NULL) ||
4951 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4952 DEPTH++;
4953 CONT = CONT->c2;
4954 goto cont;
4955 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004956 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4957 ret = (CONT->c1->prefix == NULL);
4958 } else if (CONT->c1->prefix == NULL) {
4959 ret = 0;
4960 } else {
4961 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4962 }
4963 if (ret == 0) {
4964 DEPTH++;
4965 CONT = CONT->c2;
4966 goto cont;
4967 }
Daniel Veillard85349052001-04-20 13:48:21 +00004968 }
4969
4970 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004971 * save the second branch 'or' branch
4972 */
4973 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004974 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4975 OCCURS, ROLLBACK_OR) < 0)
4976 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004977 DEPTH++;
4978 CONT = CONT->c1;
4979 goto cont;
4980 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004981 /*
4982 * Small optimization.
4983 */
4984 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4985 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4986 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4987 if ((NODE == NULL) ||
4988 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4989 DEPTH++;
4990 CONT = CONT->c2;
4991 goto cont;
4992 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004993 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4994 ret = (CONT->c1->prefix == NULL);
4995 } else if (CONT->c1->prefix == NULL) {
4996 ret = 0;
4997 } else {
4998 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4999 }
5000 if (ret == 0) {
5001 DEPTH++;
5002 CONT = CONT->c2;
5003 goto cont;
5004 }
Daniel Veillard1d047672001-06-09 16:41:01 +00005005 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005006 DEPTH++;
5007 CONT = CONT->c1;
5008 goto cont;
5009 }
5010
5011 /*
5012 * At this point handle going up in the tree
5013 */
5014 if (ret == -1) {
5015 DEBUG_VALID_MSG("error found returning");
5016 return(ret);
5017 }
5018analyze:
5019 while (CONT != NULL) {
5020 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005021 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005022 * this level.
5023 */
5024 if (ret == 0) {
5025 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005026 xmlNodePtr cur;
5027
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005028 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005029 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005030 DEBUG_VALID_MSG("Once branch failed, rollback");
5031 if (vstateVPop(ctxt) < 0 ) {
5032 DEBUG_VALID_MSG("exhaustion, failed");
5033 return(0);
5034 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005035 if (cur != ctxt->vstate->node)
5036 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005037 goto cont;
5038 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00005039 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005040 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005041 DEBUG_VALID_MSG("Plus branch failed, rollback");
5042 if (vstateVPop(ctxt) < 0 ) {
5043 DEBUG_VALID_MSG("exhaustion, failed");
5044 return(0);
5045 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005046 if (cur != ctxt->vstate->node)
5047 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005048 goto cont;
5049 }
5050 DEBUG_VALID_MSG("Plus branch found");
5051 ret = 1;
5052 break;
5053 case XML_ELEMENT_CONTENT_MULT:
5054#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00005055 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005056 DEBUG_VALID_MSG("Mult branch failed");
5057 } else {
5058 DEBUG_VALID_MSG("Mult branch found");
5059 }
5060#endif
5061 ret = 1;
5062 break;
5063 case XML_ELEMENT_CONTENT_OPT:
5064 DEBUG_VALID_MSG("Option branch failed");
5065 ret = 1;
5066 break;
5067 }
5068 } else {
5069 switch (CONT->ocur) {
5070 case XML_ELEMENT_CONTENT_OPT:
5071 DEBUG_VALID_MSG("Option branch succeeded");
5072 ret = 1;
5073 break;
5074 case XML_ELEMENT_CONTENT_ONCE:
5075 DEBUG_VALID_MSG("Once branch succeeded");
5076 ret = 1;
5077 break;
5078 case XML_ELEMENT_CONTENT_PLUS:
5079 if (STATE == ROLLBACK_PARENT) {
5080 DEBUG_VALID_MSG("Plus branch rollback");
5081 ret = 1;
5082 break;
5083 }
5084 if (NODE == NULL) {
5085 DEBUG_VALID_MSG("Plus branch exhausted");
5086 ret = 1;
5087 break;
5088 }
5089 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00005090 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005091 goto cont;
5092 case XML_ELEMENT_CONTENT_MULT:
5093 if (STATE == ROLLBACK_PARENT) {
5094 DEBUG_VALID_MSG("Mult branch rollback");
5095 ret = 1;
5096 break;
5097 }
5098 if (NODE == NULL) {
5099 DEBUG_VALID_MSG("Mult branch exhausted");
5100 ret = 1;
5101 break;
5102 }
5103 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00005104 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005105 goto cont;
5106 }
5107 }
5108 STATE = 0;
5109
5110 /*
5111 * Then act accordingly at the parent level
5112 */
Daniel Veillard5344c602001-12-31 16:37:34 +00005113 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005114 if (CONT->parent == NULL)
5115 break;
5116
5117 switch (CONT->parent->type) {
5118 case XML_ELEMENT_CONTENT_PCDATA:
5119 DEBUG_VALID_MSG("Error: parent pcdata");
5120 return(-1);
5121 case XML_ELEMENT_CONTENT_ELEMENT:
5122 DEBUG_VALID_MSG("Error: parent element");
5123 return(-1);
5124 case XML_ELEMENT_CONTENT_OR:
5125 if (ret == 1) {
5126 DEBUG_VALID_MSG("Or succeeded");
5127 CONT = CONT->parent;
5128 DEPTH--;
5129 } else {
5130 DEBUG_VALID_MSG("Or failed");
5131 CONT = CONT->parent;
5132 DEPTH--;
5133 }
5134 break;
5135 case XML_ELEMENT_CONTENT_SEQ:
5136 if (ret == 0) {
5137 DEBUG_VALID_MSG("Sequence failed");
5138 CONT = CONT->parent;
5139 DEPTH--;
5140 } else if (CONT == CONT->parent->c1) {
5141 DEBUG_VALID_MSG("Sequence testing 2nd branch");
5142 CONT = CONT->parent->c2;
5143 goto cont;
5144 } else {
5145 DEBUG_VALID_MSG("Sequence succeeded");
5146 CONT = CONT->parent;
5147 DEPTH--;
5148 }
5149 }
5150 }
5151 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005152 xmlNodePtr cur;
5153
5154 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005155 DEBUG_VALID_MSG("Failed, remaining input, rollback");
5156 if (vstateVPop(ctxt) < 0 ) {
5157 DEBUG_VALID_MSG("exhaustion, failed");
5158 return(0);
5159 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005160 if (cur != ctxt->vstate->node)
5161 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005162 goto cont;
5163 }
5164 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005165 xmlNodePtr cur;
5166
5167 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005168 DEBUG_VALID_MSG("Failure, rollback");
5169 if (vstateVPop(ctxt) < 0 ) {
5170 DEBUG_VALID_MSG("exhaustion, failed");
5171 return(0);
5172 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005173 if (cur != ctxt->vstate->node)
5174 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005175 goto cont;
5176 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005177 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005178}
Daniel Veillard23e73572002-09-19 19:56:43 +00005179#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005180
5181/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00005182 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005183 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00005184 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005185 * @content: An element
5186 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5187 *
5188 * This will dump the list of elements to the buffer
5189 * Intended just for the debug routine
5190 */
5191static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00005192xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005193 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00005194 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005195
5196 if (node == NULL) return;
5197 if (glob) strcat(buf, "(");
5198 cur = node;
5199 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005200 len = strlen(buf);
5201 if (size - len < 50) {
5202 if ((size - len > 4) && (buf[len - 1] != '.'))
5203 strcat(buf, " ...");
5204 return;
5205 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005206 switch (cur->type) {
5207 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005208 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005209 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005210 if ((size - len > 4) && (buf[len - 1] != '.'))
5211 strcat(buf, " ...");
5212 return;
5213 }
5214 strcat(buf, (char *) cur->ns->prefix);
5215 strcat(buf, ":");
5216 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005217 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005218 if ((size - len > 4) && (buf[len - 1] != '.'))
5219 strcat(buf, " ...");
5220 return;
5221 }
5222 strcat(buf, (char *) cur->name);
5223 if (cur->next != NULL)
5224 strcat(buf, " ");
5225 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005226 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005227 if (xmlIsBlankNode(cur))
5228 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005229 case XML_CDATA_SECTION_NODE:
5230 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005231 strcat(buf, "CDATA");
5232 if (cur->next != NULL)
5233 strcat(buf, " ");
5234 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005235 case XML_ATTRIBUTE_NODE:
5236 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005237#ifdef LIBXML_DOCB_ENABLED
5238 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005239#endif
5240 case XML_HTML_DOCUMENT_NODE:
5241 case XML_DOCUMENT_TYPE_NODE:
5242 case XML_DOCUMENT_FRAG_NODE:
5243 case XML_NOTATION_NODE:
5244 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005245 strcat(buf, "???");
5246 if (cur->next != NULL)
5247 strcat(buf, " ");
5248 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005249 case XML_ENTITY_NODE:
5250 case XML_PI_NODE:
5251 case XML_DTD_NODE:
5252 case XML_COMMENT_NODE:
5253 case XML_ELEMENT_DECL:
5254 case XML_ATTRIBUTE_DECL:
5255 case XML_ENTITY_DECL:
5256 case XML_XINCLUDE_START:
5257 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005258 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005259 }
5260 cur = cur->next;
5261 }
5262 if (glob) strcat(buf, ")");
5263}
5264
5265/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005266 * xmlValidateElementContent:
5267 * @ctxt: the validation context
5268 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005269 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005270 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005271 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005272 *
5273 * Try to validate the content model of an element
5274 *
5275 * returns 1 if valid or 0 if not and -1 in case of error
5276 */
5277
5278static int
5279xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005280 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00005281 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00005282#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00005283 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00005284#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00005285 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005286 xmlElementContentPtr cont;
5287 const xmlChar *name;
5288
5289 if (elemDecl == NULL)
5290 return(-1);
5291 cont = elemDecl->content;
5292 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005293
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005294#ifdef LIBXML_REGEXP_ENABLED
5295 /* Build the regexp associated to the content model */
5296 if (elemDecl->contModel == NULL)
5297 ret = xmlValidBuildContentModel(ctxt, elemDecl);
5298 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005299 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005300 } else {
5301 xmlRegExecCtxtPtr exec;
5302
Daniel Veillardec498e12003-02-05 11:01:50 +00005303 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5304 return(-1);
5305 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005306 ctxt->nodeMax = 0;
5307 ctxt->nodeNr = 0;
5308 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005309 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5310 if (exec != NULL) {
5311 cur = child;
5312 while (cur != NULL) {
5313 switch (cur->type) {
5314 case XML_ENTITY_REF_NODE:
5315 /*
5316 * Push the current node to be able to roll back
5317 * and process within the entity
5318 */
5319 if ((cur->children != NULL) &&
5320 (cur->children->children != NULL)) {
5321 nodeVPush(ctxt, cur);
5322 cur = cur->children->children;
5323 continue;
5324 }
5325 break;
5326 case XML_TEXT_NODE:
5327 if (xmlIsBlankNode(cur))
5328 break;
5329 ret = 0;
5330 goto fail;
5331 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00005332 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005333 ret = 0;
5334 goto fail;
5335 case XML_ELEMENT_NODE:
5336 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005337 xmlChar fn[50];
5338 xmlChar *fullname;
5339
5340 fullname = xmlBuildQName(cur->name,
5341 cur->ns->prefix, fn, 50);
5342 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005343 ret = -1;
5344 goto fail;
5345 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005346 ret = xmlRegExecPushString(exec, fullname, NULL);
5347 if ((fullname != fn) && (fullname != cur->name))
5348 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005349 } else {
5350 ret = xmlRegExecPushString(exec, cur->name, NULL);
5351 }
5352 break;
5353 default:
5354 break;
5355 }
5356 /*
5357 * Switch to next element
5358 */
5359 cur = cur->next;
5360 while (cur == NULL) {
5361 cur = nodeVPop(ctxt);
5362 if (cur == NULL)
5363 break;
5364 cur = cur->next;
5365 }
5366 }
5367 ret = xmlRegExecPushString(exec, NULL, NULL);
5368fail:
5369 xmlRegFreeExecCtxt(exec);
5370 }
5371 }
5372#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005373 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005374 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005375 */
5376 ctxt->vstateMax = 8;
5377 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5378 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5379 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005380 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005381 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005382 }
5383 /*
5384 * The first entry in the stack is reserved to the current state
5385 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005386 ctxt->nodeMax = 0;
5387 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005388 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005389 ctxt->vstate = &ctxt->vstateTab[0];
5390 ctxt->vstateNr = 1;
5391 CONT = cont;
5392 NODE = child;
5393 DEPTH = 0;
5394 OCCURS = 0;
5395 STATE = 0;
5396 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005397 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005398 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5399 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005400 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005401 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005402 /*
5403 * An entities reference appeared at this level.
5404 * Buid a minimal representation of this node content
5405 * sufficient to run the validation process on it
5406 */
5407 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005408 cur = child;
5409 while (cur != NULL) {
5410 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005411 case XML_ENTITY_REF_NODE:
5412 /*
5413 * Push the current node to be able to roll back
5414 * and process within the entity
5415 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005416 if ((cur->children != NULL) &&
5417 (cur->children->children != NULL)) {
5418 nodeVPush(ctxt, cur);
5419 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005420 continue;
5421 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005422 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005423 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005424 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005425 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005426 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005427 case XML_CDATA_SECTION_NODE:
5428 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005429 case XML_ELEMENT_NODE:
5430 /*
5431 * Allocate a new node and minimally fills in
5432 * what's required
5433 */
5434 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5435 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005436 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005437 xmlFreeNodeList(repl);
5438 ret = -1;
5439 goto done;
5440 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005441 tmp->type = cur->type;
5442 tmp->name = cur->name;
5443 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005444 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005445 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005446 if (repl == NULL)
5447 repl = last = tmp;
5448 else {
5449 last->next = tmp;
5450 last = tmp;
5451 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005452 if (cur->type == XML_CDATA_SECTION_NODE) {
5453 /*
5454 * E59 spaces in CDATA does not match the
5455 * nonterminal S
5456 */
5457 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5458 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005459 break;
5460 default:
5461 break;
5462 }
5463 /*
5464 * Switch to next element
5465 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005466 cur = cur->next;
5467 while (cur == NULL) {
5468 cur = nodeVPop(ctxt);
5469 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005470 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005471 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005472 }
5473 }
5474
5475 /*
5476 * Relaunch the validation
5477 */
5478 ctxt->vstate = &ctxt->vstateTab[0];
5479 ctxt->vstateNr = 1;
5480 CONT = cont;
5481 NODE = repl;
5482 DEPTH = 0;
5483 OCCURS = 0;
5484 STATE = 0;
5485 ret = xmlValidateElementType(ctxt);
5486 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005487#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005488 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00005489 if (ctxt != NULL) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005490 char expr[5000];
5491 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005492
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005493 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005494 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005495 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005496#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005497 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005498 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005499 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005500#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005501 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005502
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005503 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005504 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5505 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5506 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005507 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005508 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5509 "Element content does not follow the DTD, expecting %s, got %s\n",
5510 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005511 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005512 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005513 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005514 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005515 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005516 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005517 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005518 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5519 "Element content does not follow the DTD\n",
5520 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005521 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005522 }
5523 ret = 0;
5524 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005525 if (ret == -3)
5526 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005527
Daniel Veillard23e73572002-09-19 19:56:43 +00005528#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005529done:
5530 /*
5531 * Deallocate the copy if done, and free up the validation stack
5532 */
5533 while (repl != NULL) {
5534 tmp = repl->next;
5535 xmlFree(repl);
5536 repl = tmp;
5537 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005538 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005539 if (ctxt->vstateTab != NULL) {
5540 xmlFree(ctxt->vstateTab);
5541 ctxt->vstateTab = NULL;
5542 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005543#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005544 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005545 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005546 if (ctxt->nodeTab != NULL) {
5547 xmlFree(ctxt->nodeTab);
5548 ctxt->nodeTab = NULL;
5549 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005550 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005551
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005552}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005553
Owen Taylor3473f882001-02-23 17:55:21 +00005554/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005555 * xmlValidateCdataElement:
5556 * @ctxt: the validation context
5557 * @doc: a document instance
5558 * @elem: an element instance
5559 *
5560 * Check that an element follows #CDATA
5561 *
5562 * returns 1 if valid or 0 otherwise
5563 */
5564static int
5565xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5566 xmlNodePtr elem) {
5567 int ret = 1;
5568 xmlNodePtr cur, child;
5569
Daniel Veillardceb09b92002-10-04 11:46:37 +00005570 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005571 return(0);
5572
5573 child = elem->children;
5574
5575 cur = child;
5576 while (cur != NULL) {
5577 switch (cur->type) {
5578 case XML_ENTITY_REF_NODE:
5579 /*
5580 * Push the current node to be able to roll back
5581 * and process within the entity
5582 */
5583 if ((cur->children != NULL) &&
5584 (cur->children->children != NULL)) {
5585 nodeVPush(ctxt, cur);
5586 cur = cur->children->children;
5587 continue;
5588 }
5589 break;
5590 case XML_COMMENT_NODE:
5591 case XML_PI_NODE:
5592 case XML_TEXT_NODE:
5593 case XML_CDATA_SECTION_NODE:
5594 break;
5595 default:
5596 ret = 0;
5597 goto done;
5598 }
5599 /*
5600 * Switch to next element
5601 */
5602 cur = cur->next;
5603 while (cur == NULL) {
5604 cur = nodeVPop(ctxt);
5605 if (cur == NULL)
5606 break;
5607 cur = cur->next;
5608 }
5609 }
5610done:
5611 ctxt->nodeMax = 0;
5612 ctxt->nodeNr = 0;
5613 if (ctxt->nodeTab != NULL) {
5614 xmlFree(ctxt->nodeTab);
5615 ctxt->nodeTab = NULL;
5616 }
5617 return(ret);
5618}
5619
5620/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005621 * xmlValidateCheckMixed:
5622 * @ctxt: the validation context
5623 * @cont: the mixed content model
5624 * @qname: the qualified name as appearing in the serialization
5625 *
5626 * Check if the given node is part of the content model.
5627 *
5628 * Returns 1 if yes, 0 if no, -1 in case of error
5629 */
5630static int
William M. Brackedb65a72004-02-06 07:36:04 +00005631xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005632 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005633 const xmlChar *name;
5634 int plen;
5635 name = xmlSplitQName3(qname, &plen);
5636
5637 if (name == NULL) {
5638 while (cont != NULL) {
5639 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5640 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5641 return(1);
5642 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5643 (cont->c1 != NULL) &&
5644 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5645 if ((cont->c1->prefix == NULL) &&
5646 (xmlStrEqual(cont->c1->name, qname)))
5647 return(1);
5648 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5649 (cont->c1 == NULL) ||
5650 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005651 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5652 "Internal: MIXED struct corrupted\n",
5653 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005654 break;
5655 }
5656 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005657 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005658 } else {
5659 while (cont != NULL) {
5660 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5661 if ((cont->prefix != NULL) &&
5662 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5663 (xmlStrEqual(cont->name, name)))
5664 return(1);
5665 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5666 (cont->c1 != NULL) &&
5667 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5668 if ((cont->c1->prefix != NULL) &&
5669 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5670 (xmlStrEqual(cont->c1->name, name)))
5671 return(1);
5672 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5673 (cont->c1 == NULL) ||
5674 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005675 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5676 "Internal: MIXED struct corrupted\n",
5677 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005678 break;
5679 }
5680 cont = cont->c2;
5681 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005682 }
5683 return(0);
5684}
5685
5686/**
5687 * xmlValidGetElemDecl:
5688 * @ctxt: the validation context
5689 * @doc: a document instance
5690 * @elem: an element instance
5691 * @extsubset: pointer, (out) indicate if the declaration was found
5692 * in the external subset.
5693 *
5694 * Finds a declaration associated to an element in the document.
5695 *
5696 * returns the pointer to the declaration or NULL if not found.
5697 */
5698static xmlElementPtr
5699xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5700 xmlNodePtr elem, int *extsubset) {
5701 xmlElementPtr elemDecl = NULL;
5702 const xmlChar *prefix = NULL;
5703
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005704 if ((ctxt == NULL) || (doc == NULL) ||
5705 (elem == NULL) || (elem->name == NULL))
5706 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005707 if (extsubset != NULL)
5708 *extsubset = 0;
5709
5710 /*
5711 * Fetch the declaration for the qualified name
5712 */
5713 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5714 prefix = elem->ns->prefix;
5715
5716 if (prefix != NULL) {
5717 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5718 elem->name, prefix);
5719 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5720 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5721 elem->name, prefix);
5722 if ((elemDecl != NULL) && (extsubset != NULL))
5723 *extsubset = 1;
5724 }
5725 }
5726
5727 /*
5728 * Fetch the declaration for the non qualified name
5729 * This is "non-strict" validation should be done on the
5730 * full QName but in that case being flexible makes sense.
5731 */
5732 if (elemDecl == NULL) {
5733 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5734 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5735 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5736 if ((elemDecl != NULL) && (extsubset != NULL))
5737 *extsubset = 1;
5738 }
5739 }
5740 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005741 xmlErrValidNode(ctxt, elem,
5742 XML_DTD_UNKNOWN_ELEM,
5743 "No declaration for element %s\n",
5744 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005745 }
5746 return(elemDecl);
5747}
5748
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005749#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005750/**
5751 * xmlValidatePushElement:
5752 * @ctxt: the validation context
5753 * @doc: a document instance
5754 * @elem: an element instance
5755 * @qname: the qualified name as appearing in the serialization
5756 *
5757 * Push a new element start on the validation stack.
5758 *
5759 * returns 1 if no validation problem was found or 0 otherwise
5760 */
5761int
5762xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5763 xmlNodePtr elem, const xmlChar *qname) {
5764 int ret = 1;
5765 xmlElementPtr eDecl;
5766 int extsubset = 0;
5767
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005768 if (ctxt == NULL)
5769 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005770/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005771 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5772 xmlValidStatePtr state = ctxt->vstate;
5773 xmlElementPtr elemDecl;
5774
5775 /*
5776 * Check the new element agaisnt the content model of the new elem.
5777 */
5778 if (state->elemDecl != NULL) {
5779 elemDecl = state->elemDecl;
5780
5781 switch(elemDecl->etype) {
5782 case XML_ELEMENT_TYPE_UNDEFINED:
5783 ret = 0;
5784 break;
5785 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005786 xmlErrValidNode(ctxt, state->node,
5787 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005788 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005789 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005790 ret = 0;
5791 break;
5792 case XML_ELEMENT_TYPE_ANY:
5793 /* I don't think anything is required then */
5794 break;
5795 case XML_ELEMENT_TYPE_MIXED:
5796 /* simple case of declared as #PCDATA */
5797 if ((elemDecl->content != NULL) &&
5798 (elemDecl->content->type ==
5799 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005800 xmlErrValidNode(ctxt, state->node,
5801 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005802 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005803 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005804 ret = 0;
5805 } else {
5806 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5807 qname);
5808 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005809 xmlErrValidNode(ctxt, state->node,
5810 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005811 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005812 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005813 }
5814 }
5815 break;
5816 case XML_ELEMENT_TYPE_ELEMENT:
5817 /*
5818 * TODO:
5819 * VC: Standalone Document Declaration
5820 * - element types with element content, if white space
5821 * occurs directly within any instance of those types.
5822 */
5823 if (state->exec != NULL) {
5824 ret = xmlRegExecPushString(state->exec, qname, NULL);
5825 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005826 xmlErrValidNode(ctxt, state->node,
5827 XML_DTD_CONTENT_MODEL,
5828 "Element %s content does not follow the DTD, Misplaced %s\n",
5829 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005830 ret = 0;
5831 } else {
5832 ret = 1;
5833 }
5834 }
5835 break;
5836 }
5837 }
5838 }
5839 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5840 vstateVPush(ctxt, eDecl, elem);
5841 return(ret);
5842}
5843
5844/**
5845 * xmlValidatePushCData:
5846 * @ctxt: the validation context
5847 * @data: some character data read
5848 * @len: the lenght of the data
5849 *
5850 * check the CData parsed for validation in the current stack
5851 *
5852 * returns 1 if no validation problem was found or 0 otherwise
5853 */
5854int
5855xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5856 int ret = 1;
5857
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005858/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005859 if (ctxt == NULL)
5860 return(0);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005861 if (len <= 0)
5862 return(ret);
5863 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5864 xmlValidStatePtr state = ctxt->vstate;
5865 xmlElementPtr elemDecl;
5866
5867 /*
5868 * Check the new element agaisnt the content model of the new elem.
5869 */
5870 if (state->elemDecl != NULL) {
5871 elemDecl = state->elemDecl;
5872
5873 switch(elemDecl->etype) {
5874 case XML_ELEMENT_TYPE_UNDEFINED:
5875 ret = 0;
5876 break;
5877 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005878 xmlErrValidNode(ctxt, state->node,
5879 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005880 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005881 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005882 ret = 0;
5883 break;
5884 case XML_ELEMENT_TYPE_ANY:
5885 break;
5886 case XML_ELEMENT_TYPE_MIXED:
5887 break;
5888 case XML_ELEMENT_TYPE_ELEMENT:
5889 if (len > 0) {
5890 int i;
5891
5892 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005893 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005894 xmlErrValidNode(ctxt, state->node,
5895 XML_DTD_CONTENT_MODEL,
5896 "Element %s content does not follow the DTD, Text not allowed\n",
5897 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005898 ret = 0;
5899 goto done;
5900 }
5901 }
5902 /*
5903 * TODO:
5904 * VC: Standalone Document Declaration
5905 * element types with element content, if white space
5906 * occurs directly within any instance of those types.
5907 */
5908 }
5909 break;
5910 }
5911 }
5912 }
5913done:
5914 return(ret);
5915}
5916
5917/**
5918 * xmlValidatePopElement:
5919 * @ctxt: the validation context
5920 * @doc: a document instance
5921 * @elem: an element instance
5922 * @qname: the qualified name as appearing in the serialization
5923 *
5924 * Pop the element end from the validation stack.
5925 *
5926 * returns 1 if no validation problem was found or 0 otherwise
5927 */
5928int
5929xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005930 xmlNodePtr elem ATTRIBUTE_UNUSED,
5931 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005932 int ret = 1;
5933
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005934 if (ctxt == NULL)
5935 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005936/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005937 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5938 xmlValidStatePtr state = ctxt->vstate;
5939 xmlElementPtr elemDecl;
5940
5941 /*
5942 * Check the new element agaisnt the content model of the new elem.
5943 */
5944 if (state->elemDecl != NULL) {
5945 elemDecl = state->elemDecl;
5946
5947 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5948 if (state->exec != NULL) {
5949 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5950 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005951 xmlErrValidNode(ctxt, state->node,
5952 XML_DTD_CONTENT_MODEL,
5953 "Element %s content does not follow the DTD, Expecting more child\n",
5954 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005955 } else {
5956 /*
5957 * previous validation errors should not generate
5958 * a new one here
5959 */
5960 ret = 1;
5961 }
5962 }
5963 }
5964 }
5965 vstateVPop(ctxt);
5966 }
5967 return(ret);
5968}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005969#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005970
5971/**
Owen Taylor3473f882001-02-23 17:55:21 +00005972 * xmlValidateOneElement:
5973 * @ctxt: the validation context
5974 * @doc: a document instance
5975 * @elem: an element instance
5976 *
5977 * Try to validate a single element and it's attributes,
5978 * basically it does the following checks as described by the
5979 * XML-1.0 recommendation:
5980 * - [ VC: Element Valid ]
5981 * - [ VC: Required Attribute ]
5982 * Then call xmlValidateOneAttribute() for each attribute present.
5983 *
5984 * The ID/IDREF checkings are done separately
5985 *
5986 * returns 1 if valid or 0 otherwise
5987 */
5988
5989int
5990xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5991 xmlNodePtr elem) {
5992 xmlElementPtr elemDecl = NULL;
5993 xmlElementContentPtr cont;
5994 xmlAttributePtr attr;
5995 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005996 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005997 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005998 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005999
6000 CHECK_DTD;
6001
6002 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006003 switch (elem->type) {
6004 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006005 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6006 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006007 return(0);
6008 case XML_TEXT_NODE:
6009 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006010 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6011 "Text element has children !\n",
6012 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006013 return(0);
6014 }
Owen Taylor3473f882001-02-23 17:55:21 +00006015 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006016 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6017 "Text element has namespace !\n",
6018 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006019 return(0);
6020 }
Owen Taylor3473f882001-02-23 17:55:21 +00006021 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006022 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6023 "Text element has no content !\n",
6024 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006025 return(0);
6026 }
6027 return(1);
6028 case XML_XINCLUDE_START:
6029 case XML_XINCLUDE_END:
6030 return(1);
6031 case XML_CDATA_SECTION_NODE:
6032 case XML_ENTITY_REF_NODE:
6033 case XML_PI_NODE:
6034 case XML_COMMENT_NODE:
6035 return(1);
6036 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006037 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6038 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006039 return(0);
6040 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006041 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6042 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006043 return(0);
6044 case XML_DOCUMENT_NODE:
6045 case XML_DOCUMENT_TYPE_NODE:
6046 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006047 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6048 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006049 return(0);
6050 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006051 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6052 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006053 return(0);
6054 case XML_ELEMENT_NODE:
6055 break;
6056 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006057 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6058 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006059 return(0);
6060 }
Owen Taylor3473f882001-02-23 17:55:21 +00006061
6062 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00006063 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00006064 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00006065 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
6066 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006067 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006068
Daniel Veillardea7751d2002-12-20 00:16:24 +00006069 /*
6070 * If vstateNr is not zero that means continuous validation is
6071 * activated, do not try to check the content model at that level.
6072 */
6073 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006074 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00006075 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00006076 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006077 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
6078 "No declaration for element %s\n",
6079 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00006080 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006081 case XML_ELEMENT_TYPE_EMPTY:
6082 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006083 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00006084 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006085 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006086 ret = 0;
6087 }
6088 break;
6089 case XML_ELEMENT_TYPE_ANY:
6090 /* I don't think anything is required then */
6091 break;
6092 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006093
Daniel Veillard04e2dae2001-07-09 20:07:25 +00006094 /* simple case of declared as #PCDATA */
6095 if ((elemDecl->content != NULL) &&
6096 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
6097 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
6098 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006099 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00006100 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006101 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00006102 }
6103 break;
6104 }
Owen Taylor3473f882001-02-23 17:55:21 +00006105 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00006106 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00006107 while (child != NULL) {
6108 if (child->type == XML_ELEMENT_NODE) {
6109 name = child->name;
6110 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006111 xmlChar fn[50];
6112 xmlChar *fullname;
6113
6114 fullname = xmlBuildQName(child->name, child->ns->prefix,
6115 fn, 50);
6116 if (fullname == NULL)
6117 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006118 cont = elemDecl->content;
6119 while (cont != NULL) {
6120 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006121 if (xmlStrEqual(cont->name, fullname))
6122 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006123 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6124 (cont->c1 != NULL) &&
6125 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00006126 if (xmlStrEqual(cont->c1->name, fullname))
6127 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006128 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6129 (cont->c1 == NULL) ||
6130 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006131 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
6132 "Internal: MIXED struct corrupted\n",
6133 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006134 break;
6135 }
6136 cont = cont->c2;
6137 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00006138 if ((fullname != fn) && (fullname != child->name))
6139 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00006140 if (cont != NULL)
6141 goto child_ok;
6142 }
6143 cont = elemDecl->content;
6144 while (cont != NULL) {
6145 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6146 if (xmlStrEqual(cont->name, name)) break;
6147 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6148 (cont->c1 != NULL) &&
6149 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
6150 if (xmlStrEqual(cont->c1->name, name)) break;
6151 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6152 (cont->c1 == NULL) ||
6153 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006154 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
6155 "Internal: MIXED struct corrupted\n",
6156 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006157 break;
6158 }
6159 cont = cont->c2;
6160 }
6161 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006162 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006163 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006164 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006165 ret = 0;
6166 }
6167 }
6168child_ok:
6169 child = child->next;
6170 }
6171 break;
6172 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006173 if ((doc->standalone == 1) && (extsubset == 1)) {
6174 /*
6175 * VC: Standalone Document Declaration
6176 * - element types with element content, if white space
6177 * occurs directly within any instance of those types.
6178 */
6179 child = elem->children;
6180 while (child != NULL) {
6181 if (child->type == XML_TEXT_NODE) {
6182 const xmlChar *content = child->content;
6183
William M. Brack76e95df2003-10-18 16:20:14 +00006184 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006185 content++;
6186 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006187 xmlErrValidNode(ctxt, elem,
6188 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006189"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006190 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006191 ret = 0;
6192 break;
6193 }
6194 }
6195 child =child->next;
6196 }
6197 }
Owen Taylor3473f882001-02-23 17:55:21 +00006198 child = elem->children;
6199 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00006200 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006201 if (tmp <= 0)
6202 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006203 break;
6204 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00006205 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00006206
6207 /* [ VC: Required Attribute ] */
6208 attr = elemDecl->attributes;
6209 while (attr != NULL) {
6210 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006211 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006212
Daniel Veillarde4301c82002-02-13 13:32:35 +00006213 if ((attr->prefix == NULL) &&
6214 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6215 xmlNsPtr ns;
6216
6217 ns = elem->nsDef;
6218 while (ns != NULL) {
6219 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006220 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006221 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006222 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006223 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6224 xmlNsPtr ns;
6225
6226 ns = elem->nsDef;
6227 while (ns != NULL) {
6228 if (xmlStrEqual(attr->name, ns->prefix))
6229 goto found;
6230 ns = ns->next;
6231 }
6232 } else {
6233 xmlAttrPtr attrib;
6234
6235 attrib = elem->properties;
6236 while (attrib != NULL) {
6237 if (xmlStrEqual(attrib->name, attr->name)) {
6238 if (attr->prefix != NULL) {
6239 xmlNsPtr nameSpace = attrib->ns;
6240
6241 if (nameSpace == NULL)
6242 nameSpace = elem->ns;
6243 /*
6244 * qualified names handling is problematic, having a
6245 * different prefix should be possible but DTDs don't
6246 * allow to define the URI instead of the prefix :-(
6247 */
6248 if (nameSpace == NULL) {
6249 if (qualified < 0)
6250 qualified = 0;
6251 } else if (!xmlStrEqual(nameSpace->prefix,
6252 attr->prefix)) {
6253 if (qualified < 1)
6254 qualified = 1;
6255 } else
6256 goto found;
6257 } else {
6258 /*
6259 * We should allow applications to define namespaces
6260 * for their application even if the DTD doesn't
6261 * carry one, otherwise, basically we would always
6262 * break.
6263 */
6264 goto found;
6265 }
6266 }
6267 attrib = attrib->next;
6268 }
Owen Taylor3473f882001-02-23 17:55:21 +00006269 }
6270 if (qualified == -1) {
6271 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006272 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006273 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006274 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006275 ret = 0;
6276 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006277 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006278 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00006279 elem->name, attr->prefix,attr->name);
6280 ret = 0;
6281 }
6282 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006283 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006284 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006285 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006286 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006287 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006288 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006289 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006290 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006291 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
6292 /*
6293 * Special tests checking #FIXED namespace declarations
6294 * have the right value since this is not done as an
6295 * attribute checking
6296 */
6297 if ((attr->prefix == NULL) &&
6298 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6299 xmlNsPtr ns;
6300
6301 ns = elem->nsDef;
6302 while (ns != NULL) {
6303 if (ns->prefix == NULL) {
6304 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006305 xmlErrValidNode(ctxt, elem,
6306 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00006307 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006308 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006309 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006310 }
6311 goto found;
6312 }
6313 ns = ns->next;
6314 }
6315 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6316 xmlNsPtr ns;
6317
6318 ns = elem->nsDef;
6319 while (ns != NULL) {
6320 if (xmlStrEqual(attr->name, ns->prefix)) {
6321 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006322 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006323 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006324 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006325 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006326 }
6327 goto found;
6328 }
6329 ns = ns->next;
6330 }
6331 }
Owen Taylor3473f882001-02-23 17:55:21 +00006332 }
6333found:
6334 attr = attr->nexth;
6335 }
6336 return(ret);
6337}
6338
6339/**
6340 * xmlValidateRoot:
6341 * @ctxt: the validation context
6342 * @doc: a document instance
6343 *
6344 * Try to validate a the root element
6345 * basically it does the following check as described by the
6346 * XML-1.0 recommendation:
6347 * - [ VC: Root Element Type ]
6348 * it doesn't try to recurse or apply other check to the element
6349 *
6350 * returns 1 if valid or 0 otherwise
6351 */
6352
6353int
6354xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6355 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006356 int ret;
6357
Owen Taylor3473f882001-02-23 17:55:21 +00006358 if (doc == NULL) return(0);
6359
6360 root = xmlDocGetRootElement(doc);
6361 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006362 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6363 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006364 return(0);
6365 }
6366
6367 /*
6368 * When doing post validation against a separate DTD, those may
6369 * no internal subset has been generated
6370 */
6371 if ((doc->intSubset != NULL) &&
6372 (doc->intSubset->name != NULL)) {
6373 /*
6374 * Check first the document root against the NQName
6375 */
6376 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6377 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006378 xmlChar fn[50];
6379 xmlChar *fullname;
6380
6381 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6382 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006383 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006384 return(0);
6385 }
6386 ret = xmlStrEqual(doc->intSubset->name, fullname);
6387 if ((fullname != fn) && (fullname != root->name))
6388 xmlFree(fullname);
6389 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006390 goto name_ok;
6391 }
6392 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6393 (xmlStrEqual(root->name, BAD_CAST "html")))
6394 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006395 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6396 "root and DTD name do not match '%s' and '%s'\n",
6397 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006398 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006399 }
6400 }
6401name_ok:
6402 return(1);
6403}
6404
6405
6406/**
6407 * xmlValidateElement:
6408 * @ctxt: the validation context
6409 * @doc: a document instance
6410 * @elem: an element instance
6411 *
6412 * Try to validate the subtree under an element
6413 *
6414 * returns 1 if valid or 0 otherwise
6415 */
6416
6417int
6418xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6419 xmlNodePtr child;
6420 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006421 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006422 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006423 int ret = 1;
6424
6425 if (elem == NULL) return(0);
6426
6427 /*
6428 * XInclude elements were added after parsing in the infoset,
6429 * they don't really mean anything validation wise.
6430 */
6431 if ((elem->type == XML_XINCLUDE_START) ||
6432 (elem->type == XML_XINCLUDE_END))
6433 return(1);
6434
6435 CHECK_DTD;
6436
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006437 /*
6438 * Entities references have to be handled separately
6439 */
6440 if (elem->type == XML_ENTITY_REF_NODE) {
6441 return(1);
6442 }
6443
Owen Taylor3473f882001-02-23 17:55:21 +00006444 ret &= xmlValidateOneElement(ctxt, doc, elem);
Daniel Veillard8874b942005-08-25 13:19:21 +00006445 if (elem->type == XML_ELEMENT_NODE) {
6446 attr = elem->properties;
6447 while (attr != NULL) {
6448 value = xmlNodeListGetString(doc, attr->children, 0);
6449 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6450 if (value != NULL)
6451 xmlFree((char *)value);
6452 attr= attr->next;
6453 }
6454 ns = elem->nsDef;
6455 while (ns != NULL) {
6456 if (elem->ns == NULL)
6457 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6458 ns, ns->href);
6459 else
6460 ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6461 elem->ns->prefix, ns, ns->href);
6462 ns = ns->next;
6463 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006464 }
Owen Taylor3473f882001-02-23 17:55:21 +00006465 child = elem->children;
6466 while (child != NULL) {
6467 ret &= xmlValidateElement(ctxt, doc, child);
6468 child = child->next;
6469 }
6470
6471 return(ret);
6472}
6473
Daniel Veillard8730c562001-02-26 10:49:57 +00006474/**
6475 * xmlValidateRef:
6476 * @ref: A reference to be validated
6477 * @ctxt: Validation context
6478 * @name: Name of ID we are searching for
6479 *
6480 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006481static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006482xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006483 const xmlChar *name) {
6484 xmlAttrPtr id;
6485 xmlAttrPtr attr;
6486
6487 if (ref == NULL)
6488 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006489 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006490 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006491 attr = ref->attr;
6492 if (attr == NULL) {
6493 xmlChar *dup, *str = NULL, *cur, save;
6494
6495 dup = xmlStrdup(name);
6496 if (dup == NULL) {
6497 ctxt->valid = 0;
6498 return;
6499 }
6500 cur = dup;
6501 while (*cur != 0) {
6502 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006503 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006504 save = *cur;
6505 *cur = 0;
6506 id = xmlGetID(ctxt->doc, str);
6507 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006508 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006509 "attribute %s line %d references an unknown ID \"%s\"\n",
6510 ref->name, ref->lineno, str);
6511 ctxt->valid = 0;
6512 }
6513 if (save == 0)
6514 break;
6515 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006516 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006517 }
6518 xmlFree(dup);
6519 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006520 id = xmlGetID(ctxt->doc, name);
6521 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006522 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006523 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006524 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006525 ctxt->valid = 0;
6526 }
6527 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6528 xmlChar *dup, *str = NULL, *cur, save;
6529
6530 dup = xmlStrdup(name);
6531 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006532 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006533 ctxt->valid = 0;
6534 return;
6535 }
6536 cur = dup;
6537 while (*cur != 0) {
6538 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006539 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006540 save = *cur;
6541 *cur = 0;
6542 id = xmlGetID(ctxt->doc, str);
6543 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006544 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006545 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006546 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006547 ctxt->valid = 0;
6548 }
6549 if (save == 0)
6550 break;
6551 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006552 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006553 }
6554 xmlFree(dup);
6555 }
6556}
6557
6558/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006559 * xmlWalkValidateList:
6560 * @data: Contents of current link
6561 * @user: Value supplied by the user
6562 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006563 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006564 */
6565static int
6566xmlWalkValidateList(const void *data, const void *user)
6567{
6568 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6569 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6570 return 1;
6571}
6572
6573/**
6574 * xmlValidateCheckRefCallback:
6575 * @ref_list: List of references
6576 * @ctxt: Validation context
6577 * @name: Name of ID we are searching for
6578 *
6579 */
6580static void
6581xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6582 const xmlChar *name) {
6583 xmlValidateMemo memo;
6584
6585 if (ref_list == NULL)
6586 return;
6587 memo.ctxt = ctxt;
6588 memo.name = name;
6589
6590 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6591
6592}
6593
6594/**
Owen Taylor3473f882001-02-23 17:55:21 +00006595 * xmlValidateDocumentFinal:
6596 * @ctxt: the validation context
6597 * @doc: a document instance
6598 *
6599 * Does the final step for the document validation once all the
6600 * incremental validation steps have been completed
6601 *
6602 * basically it does the following checks described by the XML Rec
6603 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006604 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006605 *
6606 * returns 1 if valid or 0 otherwise
6607 */
6608
6609int
6610xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6611 xmlRefTablePtr table;
6612
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006613 if (ctxt == NULL)
6614 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006615 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006616 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6617 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006618 return(0);
6619 }
6620
6621 /*
6622 * Check all the NOTATION/NOTATIONS attributes
6623 */
6624 /*
6625 * Check all the ENTITY/ENTITIES attributes definition for validity
6626 */
6627 /*
6628 * Check all the IDREF/IDREFS attributes definition for validity
6629 */
6630 table = (xmlRefTablePtr) doc->refs;
6631 ctxt->doc = doc;
6632 ctxt->valid = 1;
6633 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6634 return(ctxt->valid);
6635}
6636
6637/**
6638 * xmlValidateDtd:
6639 * @ctxt: the validation context
6640 * @doc: a document instance
6641 * @dtd: a dtd instance
6642 *
6643 * Try to validate the document against the dtd instance
6644 *
William M. Brack367df6e2004-10-23 18:14:36 +00006645 * Basically it does check all the definitions in the DtD.
6646 * Note the the internal subset (if present) is de-coupled
6647 * (i.e. not used), which could give problems if ID or IDREF
6648 * is present.
Owen Taylor3473f882001-02-23 17:55:21 +00006649 *
6650 * returns 1 if valid or 0 otherwise
6651 */
6652
6653int
6654xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6655 int ret;
William M. Brack367df6e2004-10-23 18:14:36 +00006656 xmlDtdPtr oldExt, oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006657 xmlNodePtr root;
6658
6659 if (dtd == NULL) return(0);
6660 if (doc == NULL) return(0);
6661 oldExt = doc->extSubset;
William M. Brack367df6e2004-10-23 18:14:36 +00006662 oldInt = doc->intSubset;
Owen Taylor3473f882001-02-23 17:55:21 +00006663 doc->extSubset = dtd;
William M. Brack367df6e2004-10-23 18:14:36 +00006664 doc->intSubset = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006665 ret = xmlValidateRoot(ctxt, doc);
6666 if (ret == 0) {
6667 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006668 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006669 return(ret);
6670 }
6671 if (doc->ids != NULL) {
6672 xmlFreeIDTable(doc->ids);
6673 doc->ids = NULL;
6674 }
6675 if (doc->refs != NULL) {
6676 xmlFreeRefTable(doc->refs);
6677 doc->refs = NULL;
6678 }
6679 root = xmlDocGetRootElement(doc);
6680 ret = xmlValidateElement(ctxt, doc, root);
6681 ret &= xmlValidateDocumentFinal(ctxt, doc);
6682 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006683 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006684 return(ret);
6685}
6686
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006687static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006688xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6689 const xmlChar *name ATTRIBUTE_UNUSED) {
6690 if (cur == NULL)
6691 return;
6692 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6693 xmlChar *notation = cur->content;
6694
Daniel Veillard878eab02002-02-19 13:46:09 +00006695 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006696 int ret;
6697
6698 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6699 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006700 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006701 }
6702 }
6703 }
6704}
6705
6706static void
Owen Taylor3473f882001-02-23 17:55:21 +00006707xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006708 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006709 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006710 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006711 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006712
Owen Taylor3473f882001-02-23 17:55:21 +00006713 if (cur == NULL)
6714 return;
6715 switch (cur->atype) {
6716 case XML_ATTRIBUTE_CDATA:
6717 case XML_ATTRIBUTE_ID:
6718 case XML_ATTRIBUTE_IDREF :
6719 case XML_ATTRIBUTE_IDREFS:
6720 case XML_ATTRIBUTE_NMTOKEN:
6721 case XML_ATTRIBUTE_NMTOKENS:
6722 case XML_ATTRIBUTE_ENUMERATION:
6723 break;
6724 case XML_ATTRIBUTE_ENTITY:
6725 case XML_ATTRIBUTE_ENTITIES:
6726 case XML_ATTRIBUTE_NOTATION:
6727 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006728
6729 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6730 cur->atype, cur->defaultValue);
6731 if ((ret == 0) && (ctxt->valid == 1))
6732 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006733 }
6734 if (cur->tree != NULL) {
6735 xmlEnumerationPtr tree = cur->tree;
6736 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006737 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006738 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006739 if ((ret == 0) && (ctxt->valid == 1))
6740 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006741 tree = tree->next;
6742 }
6743 }
6744 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006745 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6746 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006747 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006748 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006749 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006750 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006751 return;
6752 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006753
6754 if (doc != NULL)
6755 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6756 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006757 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006758 if ((elem == NULL) && (cur->parent != NULL) &&
6759 (cur->parent->type == XML_DTD_NODE))
6760 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006761 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006762 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006763 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006764 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006765 return;
6766 }
6767 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006768 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006769 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006770 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006771 ctxt->valid = 0;
6772 }
6773 }
Owen Taylor3473f882001-02-23 17:55:21 +00006774}
6775
6776/**
6777 * xmlValidateDtdFinal:
6778 * @ctxt: the validation context
6779 * @doc: a document instance
6780 *
6781 * Does the final step for the dtds validation once all the
6782 * subsets have been parsed
6783 *
6784 * basically it does the following checks described by the XML Rec
6785 * - check that ENTITY and ENTITIES type attributes default or
6786 * possible values matches one of the defined entities.
6787 * - check that NOTATION type attributes default or
6788 * possible values matches one of the defined notations.
6789 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006790 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006791 */
6792
6793int
6794xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006795 xmlDtdPtr dtd;
6796 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006797 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006798
Daniel Veillard2cba4152008-08-27 11:45:41 +00006799 if ((doc == NULL) || (ctxt == NULL)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006800 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6801 return(0);
6802 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006803 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006804 dtd = doc->intSubset;
6805 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6806 table = (xmlAttributeTablePtr) dtd->attributes;
6807 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006808 }
6809 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006810 entities = (xmlEntitiesTablePtr) dtd->entities;
6811 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6812 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006813 }
6814 dtd = doc->extSubset;
6815 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6816 table = (xmlAttributeTablePtr) dtd->attributes;
6817 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006818 }
6819 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006820 entities = (xmlEntitiesTablePtr) dtd->entities;
6821 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6822 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006823 }
6824 return(ctxt->valid);
6825}
6826
6827/**
6828 * xmlValidateDocument:
6829 * @ctxt: the validation context
6830 * @doc: a document instance
6831 *
6832 * Try to validate the document instance
6833 *
6834 * basically it does the all the checks described by the XML Rec
6835 * i.e. validates the internal and external subset (if present)
6836 * and validate the document tree.
6837 *
6838 * returns 1 if valid or 0 otherwise
6839 */
6840
6841int
6842xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6843 int ret;
6844 xmlNodePtr root;
6845
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006846 if (doc == NULL)
6847 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006848 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006849 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6850 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006851 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006852 }
Owen Taylor3473f882001-02-23 17:55:21 +00006853 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6854 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
William M. Brack8c22f9f2004-08-06 16:23:27 +00006855 xmlChar *sysID;
6856 if (doc->intSubset->SystemID != NULL) {
William M. Brackbebe7302004-08-05 06:46:47 +00006857 sysID = xmlBuildURI(doc->intSubset->SystemID,
6858 doc->URL);
William M. Brack8c22f9f2004-08-06 16:23:27 +00006859 if (sysID == NULL) {
6860 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6861 "Could not build URI for external subset \"%s\"\n",
6862 (const char *) doc->intSubset->SystemID);
6863 return 0;
6864 }
6865 } else
William M. Brackbebe7302004-08-05 06:46:47 +00006866 sysID = NULL;
William M. Brack8c22f9f2004-08-06 16:23:27 +00006867 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
William M. Brackbebe7302004-08-05 06:46:47 +00006868 (const xmlChar *)sysID);
William M. Brackbebe7302004-08-05 06:46:47 +00006869 if (sysID != NULL)
6870 xmlFree(sysID);
Owen Taylor3473f882001-02-23 17:55:21 +00006871 if (doc->extSubset == NULL) {
6872 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006873 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006874 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006875 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006876 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006877 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006878 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006879 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006880 }
6881 return(0);
6882 }
6883 }
6884
6885 if (doc->ids != NULL) {
6886 xmlFreeIDTable(doc->ids);
6887 doc->ids = NULL;
6888 }
6889 if (doc->refs != NULL) {
6890 xmlFreeRefTable(doc->refs);
6891 doc->refs = NULL;
6892 }
6893 ret = xmlValidateDtdFinal(ctxt, doc);
6894 if (!xmlValidateRoot(ctxt, doc)) return(0);
6895
6896 root = xmlDocGetRootElement(doc);
6897 ret &= xmlValidateElement(ctxt, doc, root);
6898 ret &= xmlValidateDocumentFinal(ctxt, doc);
6899 return(ret);
6900}
6901
Owen Taylor3473f882001-02-23 17:55:21 +00006902/************************************************************************
6903 * *
6904 * Routines for dynamic validation editing *
6905 * *
6906 ************************************************************************/
6907
6908/**
6909 * xmlValidGetPotentialChildren:
6910 * @ctree: an element content tree
Daniel Veillard7802ba52005-10-27 11:56:20 +00006911 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006912 * @len: a pointer to the number of element in the list
6913 * @max: the size of the array
6914 *
6915 * Build/extend a list of potential children allowed by the content tree
6916 *
6917 * returns the number of element in the list, or -1 in case of error.
6918 */
6919
6920int
Daniel Veillard7802ba52005-10-27 11:56:20 +00006921xmlValidGetPotentialChildren(xmlElementContent *ctree,
6922 const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006923 int *len, int max) {
6924 int i;
6925
Daniel Veillard7802ba52005-10-27 11:56:20 +00006926 if ((ctree == NULL) || (names == NULL) || (len == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006927 return(-1);
6928 if (*len >= max) return(*len);
6929
6930 switch (ctree->type) {
6931 case XML_ELEMENT_CONTENT_PCDATA:
6932 for (i = 0; i < *len;i++)
Daniel Veillard7802ba52005-10-27 11:56:20 +00006933 if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
6934 names[(*len)++] = BAD_CAST "#PCDATA";
Owen Taylor3473f882001-02-23 17:55:21 +00006935 break;
6936 case XML_ELEMENT_CONTENT_ELEMENT:
6937 for (i = 0; i < *len;i++)
Daniel Veillard7802ba52005-10-27 11:56:20 +00006938 if (xmlStrEqual(ctree->name, names[i])) return(*len);
6939 names[(*len)++] = ctree->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006940 break;
6941 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard7802ba52005-10-27 11:56:20 +00006942 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6943 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
Owen Taylor3473f882001-02-23 17:55:21 +00006944 break;
6945 case XML_ELEMENT_CONTENT_OR:
Daniel Veillard7802ba52005-10-27 11:56:20 +00006946 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6947 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
Owen Taylor3473f882001-02-23 17:55:21 +00006948 break;
6949 }
6950
6951 return(*len);
6952}
6953
William M. Brack9333cc22004-06-24 08:33:40 +00006954/*
6955 * Dummy function to suppress messages while we try out valid elements
6956 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00006957static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
William M. Brack9333cc22004-06-24 08:33:40 +00006958 const char *msg ATTRIBUTE_UNUSED, ...) {
6959 return;
6960}
6961
Owen Taylor3473f882001-02-23 17:55:21 +00006962/**
6963 * xmlValidGetValidElements:
6964 * @prev: an element to insert after
6965 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006966 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006967 * @max: the size of the array
6968 *
6969 * This function returns the list of authorized children to insert
6970 * within an existing tree while respecting the validity constraints
6971 * forced by the Dtd. The insertion point is defined using @prev and
6972 * @next in the following ways:
6973 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6974 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6975 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6976 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6977 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6978 *
6979 * pointers to the element names are inserted at the beginning of the array
6980 * and do not need to be freed.
6981 *
6982 * returns the number of element in the list, or -1 in case of error. If
6983 * the function returns the value @max the caller is invited to grow the
6984 * receiving array and retry.
6985 */
6986
6987int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006988xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006989 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006990 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006991 int nb_valid_elements = 0;
6992 const xmlChar *elements[256];
6993 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006994 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006995
6996 xmlNode *ref_node;
6997 xmlNode *parent;
6998 xmlNode *test_node;
6999
7000 xmlNode *prev_next;
7001 xmlNode *next_prev;
7002 xmlNode *parent_childs;
7003 xmlNode *parent_last;
7004
7005 xmlElement *element_desc;
7006
7007 if (prev == NULL && next == NULL)
7008 return(-1);
7009
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00007010 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007011 if (max <= 0) return(-1);
7012
William M. Brack9333cc22004-06-24 08:33:40 +00007013 memset(&vctxt, 0, sizeof (xmlValidCtxt));
7014 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
7015
Owen Taylor3473f882001-02-23 17:55:21 +00007016 nb_valid_elements = 0;
7017 ref_node = prev ? prev : next;
7018 parent = ref_node->parent;
7019
7020 /*
7021 * Retrieves the parent element declaration
7022 */
7023 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
7024 parent->name);
7025 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
7026 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
7027 parent->name);
7028 if (element_desc == NULL) return(-1);
7029
7030 /*
7031 * Do a backup of the current tree structure
7032 */
7033 prev_next = prev ? prev->next : NULL;
7034 next_prev = next ? next->prev : NULL;
7035 parent_childs = parent->children;
7036 parent_last = parent->last;
7037
7038 /*
7039 * Creates a dummy node and insert it into the tree
7040 */
Daniel Veillard95ddcd32004-10-26 21:53:55 +00007041 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007042 test_node->parent = parent;
7043 test_node->prev = prev;
7044 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00007045 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00007046
7047 if (prev) prev->next = test_node;
7048 else parent->children = test_node;
7049
7050 if (next) next->prev = test_node;
7051 else parent->last = test_node;
7052
7053 /*
7054 * Insert each potential child node and check if the parent is
7055 * still valid
7056 */
7057 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
7058 elements, &nb_elements, 256);
7059
7060 for (i = 0;i < nb_elements;i++) {
7061 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00007062 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007063 int j;
7064
7065 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00007066 if (xmlStrEqual(elements[i], names[j])) break;
7067 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00007068 if (nb_valid_elements >= max) break;
7069 }
7070 }
7071
7072 /*
7073 * Restore the tree structure
7074 */
7075 if (prev) prev->next = prev_next;
7076 if (next) next->prev = next_prev;
7077 parent->children = parent_childs;
7078 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00007079
7080 /*
7081 * Free up the dummy node
7082 */
7083 test_node->name = name;
7084 xmlFreeNode(test_node);
7085
Owen Taylor3473f882001-02-23 17:55:21 +00007086 return(nb_valid_elements);
7087}
Daniel Veillard4432df22003-09-28 18:58:27 +00007088#endif /* LIBXML_VALID_ENABLED */
7089
Daniel Veillard5d4644e2005-04-01 13:11:58 +00007090#define bottom_valid
7091#include "elfgcchack.h"