blob: 49fb720c9021e3d9ff1269ec13066e7153066b02 [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,
125 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/**
3795 * xmlValidateAttributeValue:
3796 * @type: an attribute type
3797 * @value: an attribute value
3798 *
3799 * Validate that the given attribute value match the proper production
3800 *
3801 * [ VC: ID ]
3802 * Values of type ID must match the Name production....
3803 *
3804 * [ VC: IDREF ]
3805 * Values of type IDREF must match the Name production, and values
3806 * of type IDREFS must match Names ...
3807 *
3808 * [ VC: Entity Name ]
3809 * Values of type ENTITY must match the Name production, values
3810 * of type ENTITIES must match Names ...
3811 *
3812 * [ VC: Name Token ]
3813 * Values of type NMTOKEN must match the Nmtoken production; values
3814 * of type NMTOKENS must match Nmtokens.
3815 *
3816 * returns 1 if valid or 0 otherwise
3817 */
3818
Daniel Veillardae0765b2008-07-31 19:54:59 +00003819static int
3820xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
3821 const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00003822 switch (type) {
3823 case XML_ATTRIBUTE_ENTITIES:
3824 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardae0765b2008-07-31 19:54:59 +00003825 return(xmlValidateNamesValueInternal(doc, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003826 case XML_ATTRIBUTE_ENTITY:
3827 case XML_ATTRIBUTE_IDREF:
3828 case XML_ATTRIBUTE_ID:
3829 case XML_ATTRIBUTE_NOTATION:
Daniel Veillardae0765b2008-07-31 19:54:59 +00003830 return(xmlValidateNameValueInternal(doc, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003831 case XML_ATTRIBUTE_NMTOKENS:
3832 case XML_ATTRIBUTE_ENUMERATION:
Daniel Veillardae0765b2008-07-31 19:54:59 +00003833 return(xmlValidateNmtokensValueInternal(doc, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003834 case XML_ATTRIBUTE_NMTOKEN:
Daniel Veillardae0765b2008-07-31 19:54:59 +00003835 return(xmlValidateNmtokenValueInternal(doc, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003836 case XML_ATTRIBUTE_CDATA:
3837 break;
3838 }
3839 return(1);
3840}
3841
Daniel Veillardae0765b2008-07-31 19:54:59 +00003842int
3843xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3844 return(xmlValidateAttributeValueInternal(NULL, type, value));
3845}
3846
Owen Taylor3473f882001-02-23 17:55:21 +00003847/**
3848 * xmlValidateAttributeValue2:
3849 * @ctxt: the validation context
3850 * @doc: the document
3851 * @name: the attribute name (used for error reporting only)
3852 * @type: the attribute type
3853 * @value: the attribute value
3854 *
3855 * Validate that the given attribute value match a given type.
3856 * This typically cannot be done before having finished parsing
3857 * the subsets.
3858 *
3859 * [ VC: IDREF ]
3860 * Values of type IDREF must match one of the declared IDs
3861 * Values of type IDREFS must match a sequence of the declared IDs
3862 * each Name must match the value of an ID attribute on some element
3863 * in the XML document; i.e. IDREF values must match the value of
3864 * some ID attribute
3865 *
3866 * [ VC: Entity Name ]
3867 * Values of type ENTITY must match one declared entity
3868 * Values of type ENTITIES must match a sequence of declared entities
3869 *
3870 * [ VC: Notation Attributes ]
3871 * all notation names in the declaration must be declared.
3872 *
3873 * returns 1 if valid or 0 otherwise
3874 */
3875
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003876static int
Owen Taylor3473f882001-02-23 17:55:21 +00003877xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3878 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3879 int ret = 1;
3880 switch (type) {
3881 case XML_ATTRIBUTE_IDREFS:
3882 case XML_ATTRIBUTE_IDREF:
3883 case XML_ATTRIBUTE_ID:
3884 case XML_ATTRIBUTE_NMTOKENS:
3885 case XML_ATTRIBUTE_ENUMERATION:
3886 case XML_ATTRIBUTE_NMTOKEN:
3887 case XML_ATTRIBUTE_CDATA:
3888 break;
3889 case XML_ATTRIBUTE_ENTITY: {
3890 xmlEntityPtr ent;
3891
3892 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003893 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003894 if ((ent == NULL) && (doc->standalone == 1)) {
3895 doc->standalone = 0;
3896 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003897 }
Owen Taylor3473f882001-02-23 17:55:21 +00003898 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003899 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3900 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003901 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003902 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003903 ret = 0;
3904 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003905 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3906 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003907 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003908 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003909 ret = 0;
3910 }
3911 break;
3912 }
3913 case XML_ATTRIBUTE_ENTITIES: {
3914 xmlChar *dup, *nam = NULL, *cur, save;
3915 xmlEntityPtr ent;
3916
3917 dup = xmlStrdup(value);
3918 if (dup == NULL)
3919 return(0);
3920 cur = dup;
3921 while (*cur != 0) {
3922 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003923 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003924 save = *cur;
3925 *cur = 0;
3926 ent = xmlGetDocEntity(doc, nam);
3927 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003928 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3929 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003930 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003931 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003932 ret = 0;
3933 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003934 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3935 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003936 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003937 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003938 ret = 0;
3939 }
3940 if (save == 0)
3941 break;
3942 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003943 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003944 }
3945 xmlFree(dup);
3946 break;
3947 }
3948 case XML_ATTRIBUTE_NOTATION: {
3949 xmlNotationPtr nota;
3950
3951 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3952 if ((nota == NULL) && (doc->extSubset != NULL))
3953 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3954
3955 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003956 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3957 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003958 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003959 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003960 ret = 0;
3961 }
3962 break;
3963 }
3964 }
3965 return(ret);
3966}
3967
3968/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003969 * xmlValidCtxtNormalizeAttributeValue:
3970 * @ctxt: the validation context
3971 * @doc: the document
3972 * @elem: the parent
3973 * @name: the attribute name
3974 * @value: the attribute value
3975 * @ctxt: the validation context or NULL
3976 *
3977 * Does the validation related extra step of the normalization of attribute
3978 * values:
3979 *
3980 * If the declared value is not CDATA, then the XML processor must further
3981 * process the normalized attribute value by discarding any leading and
3982 * trailing space (#x20) characters, and by replacing sequences of space
3983 * (#x20) characters by single space (#x20) character.
3984 *
3985 * Also check VC: Standalone Document Declaration in P32, and update
3986 * ctxt->valid accordingly
3987 *
3988 * returns a new normalized string if normalization is needed, NULL otherwise
3989 * the caller must free the returned value.
3990 */
3991
3992xmlChar *
3993xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3994 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3995 xmlChar *ret, *dst;
3996 const xmlChar *src;
3997 xmlAttributePtr attrDecl = NULL;
3998 int extsubset = 0;
3999
4000 if (doc == NULL) return(NULL);
4001 if (elem == NULL) return(NULL);
4002 if (name == NULL) return(NULL);
4003 if (value == NULL) return(NULL);
4004
4005 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004006 xmlChar fn[50];
4007 xmlChar *fullname;
4008
4009 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4010 if (fullname == NULL)
Daniel Veillard24505b02005-07-28 23:49:35 +00004011 return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00004012 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00004013 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004014 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00004015 if (attrDecl != NULL)
4016 extsubset = 1;
4017 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004018 if ((fullname != fn) && (fullname != elem->name))
4019 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00004020 }
4021 if ((attrDecl == NULL) && (doc->intSubset != NULL))
4022 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4023 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4024 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4025 if (attrDecl != NULL)
4026 extsubset = 1;
4027 }
4028
4029 if (attrDecl == NULL)
4030 return(NULL);
4031 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4032 return(NULL);
4033
4034 ret = xmlStrdup(value);
4035 if (ret == NULL)
4036 return(NULL);
4037 src = value;
4038 dst = ret;
4039 while (*src == 0x20) src++;
4040 while (*src != 0) {
4041 if (*src == 0x20) {
4042 while (*src == 0x20) src++;
4043 if (*src != 0)
4044 *dst++ = 0x20;
4045 } else {
4046 *dst++ = *src++;
4047 }
4048 }
4049 *dst = 0;
4050 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004051 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00004052"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004053 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00004054 ctxt->valid = 0;
4055 }
4056 return(ret);
4057}
4058
4059/**
Owen Taylor3473f882001-02-23 17:55:21 +00004060 * xmlValidNormalizeAttributeValue:
4061 * @doc: the document
4062 * @elem: the parent
4063 * @name: the attribute name
4064 * @value: the attribute value
4065 *
4066 * Does the validation related extra step of the normalization of attribute
4067 * values:
4068 *
4069 * If the declared value is not CDATA, then the XML processor must further
4070 * process the normalized attribute value by discarding any leading and
4071 * trailing space (#x20) characters, and by replacing sequences of space
4072 * (#x20) characters by single space (#x20) character.
4073 *
Daniel Veillard652327a2003-09-29 18:02:38 +00004074 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00004075 * the caller must free the returned value.
4076 */
4077
4078xmlChar *
4079xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
4080 const xmlChar *name, const xmlChar *value) {
4081 xmlChar *ret, *dst;
4082 const xmlChar *src;
4083 xmlAttributePtr attrDecl = NULL;
4084
4085 if (doc == NULL) return(NULL);
4086 if (elem == NULL) return(NULL);
4087 if (name == NULL) return(NULL);
4088 if (value == NULL) return(NULL);
4089
4090 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004091 xmlChar fn[50];
4092 xmlChar *fullname;
4093
4094 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4095 if (fullname == NULL)
Daniel Veillard24505b02005-07-28 23:49:35 +00004096 return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00004097 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00004098 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004099 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
4100 if ((fullname != fn) && (fullname != elem->name))
4101 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004102 }
4103 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4104 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4105 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4106
4107 if (attrDecl == NULL)
4108 return(NULL);
4109 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4110 return(NULL);
4111
4112 ret = xmlStrdup(value);
4113 if (ret == NULL)
4114 return(NULL);
4115 src = value;
4116 dst = ret;
4117 while (*src == 0x20) src++;
4118 while (*src != 0) {
4119 if (*src == 0x20) {
4120 while (*src == 0x20) src++;
4121 if (*src != 0)
4122 *dst++ = 0x20;
4123 } else {
4124 *dst++ = *src++;
4125 }
4126 }
4127 *dst = 0;
4128 return(ret);
4129}
4130
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004131static void
Owen Taylor3473f882001-02-23 17:55:21 +00004132xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00004133 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00004134 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4135}
4136
4137/**
4138 * xmlValidateAttributeDecl:
4139 * @ctxt: the validation context
4140 * @doc: a document instance
4141 * @attr: an attribute definition
4142 *
4143 * Try to validate a single attribute definition
4144 * basically it does the following checks as described by the
4145 * XML-1.0 recommendation:
4146 * - [ VC: Attribute Default Legal ]
4147 * - [ VC: Enumeration ]
4148 * - [ VC: ID Attribute Default ]
4149 *
4150 * The ID/IDREF uniqueness and matching are done separately
4151 *
4152 * returns 1 if valid or 0 otherwise
4153 */
4154
4155int
4156xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4157 xmlAttributePtr attr) {
4158 int ret = 1;
4159 int val;
4160 CHECK_DTD;
4161 if(attr == NULL) return(1);
Daniel Veillardae0765b2008-07-31 19:54:59 +00004162
Owen Taylor3473f882001-02-23 17:55:21 +00004163 /* Attribute Default Legal */
4164 /* Enumeration */
4165 if (attr->defaultValue != NULL) {
Daniel Veillardae0765b2008-07-31 19:54:59 +00004166 val = xmlValidateAttributeValueInternal(doc, attr->atype,
4167 attr->defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00004168 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004169 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004170 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004171 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004172 }
4173 ret &= val;
4174 }
4175
4176 /* ID Attribute Default */
4177 if ((attr->atype == XML_ATTRIBUTE_ID)&&
4178 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4179 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004180 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004181 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004182 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004183 ret = 0;
4184 }
4185
4186 /* One ID per Element Type */
4187 if (attr->atype == XML_ATTRIBUTE_ID) {
4188 int nbId;
4189
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004190 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00004191 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4192 attr->elem);
4193 if (elem != NULL) {
Daniel Veillarddbee0f12005-06-27 13:42:57 +00004194 nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00004195 } else {
4196 xmlAttributeTablePtr table;
4197
4198 /*
4199 * The attribute may be declared in the internal subset and the
4200 * element in the external subset.
4201 */
4202 nbId = 0;
Daniel Veillard11ce4002006-03-10 00:36:23 +00004203 if (doc->intSubset != NULL) {
4204 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4205 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
4206 xmlValidateAttributeIdCallback, &nbId);
4207 }
Owen Taylor3473f882001-02-23 17:55:21 +00004208 }
4209 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004210
4211 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004212 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4213 attr->elem, nbId, attr->name);
4214 } else if (doc->extSubset != NULL) {
4215 int extId = 0;
4216 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4217 if (elem != NULL) {
Daniel Veillarddbee0f12005-06-27 13:42:57 +00004218 extId = xmlScanIDAttributeDecl(NULL, elem, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00004219 }
4220 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004221 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 external subset : %s\n",
4223 attr->elem, extId, attr->name);
4224 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004225 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004226"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004227 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004228 }
4229 }
4230 }
4231
4232 /* Validity Constraint: Enumeration */
4233 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4234 xmlEnumerationPtr tree = attr->tree;
4235 while (tree != NULL) {
4236 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4237 tree = tree->next;
4238 }
4239 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004240 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004241"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004242 attr->defaultValue, attr->name, attr->elem);
4243 ret = 0;
4244 }
4245 }
4246
4247 return(ret);
4248}
4249
4250/**
4251 * xmlValidateElementDecl:
4252 * @ctxt: the validation context
4253 * @doc: a document instance
4254 * @elem: an element definition
4255 *
4256 * Try to validate a single element definition
4257 * basically it does the following checks as described by the
4258 * XML-1.0 recommendation:
4259 * - [ VC: One ID per Element Type ]
4260 * - [ VC: No Duplicate Types ]
4261 * - [ VC: Unique Element Type Declaration ]
4262 *
4263 * returns 1 if valid or 0 otherwise
4264 */
4265
4266int
4267xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4268 xmlElementPtr elem) {
4269 int ret = 1;
4270 xmlElementPtr tst;
4271
4272 CHECK_DTD;
4273
4274 if (elem == NULL) return(1);
4275
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004276#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00004277#ifdef LIBXML_REGEXP_ENABLED
4278 /* Build the regexp associated to the content model */
4279 ret = xmlValidBuildContentModel(ctxt, elem);
4280#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004281#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00004282
Owen Taylor3473f882001-02-23 17:55:21 +00004283 /* No Duplicate Types */
4284 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4285 xmlElementContentPtr cur, next;
4286 const xmlChar *name;
4287
4288 cur = elem->content;
4289 while (cur != NULL) {
4290 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4291 if (cur->c1 == NULL) break;
4292 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4293 name = cur->c1->name;
4294 next = cur->c2;
4295 while (next != NULL) {
4296 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00004297 if ((xmlStrEqual(next->name, name)) &&
4298 (xmlStrEqual(next->prefix, cur->prefix))) {
4299 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004300 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00004301 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004302 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004303 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004304 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004305 "Definition of %s has duplicate references of %s:%s\n",
4306 elem->name, cur->prefix, name);
4307 }
Owen Taylor3473f882001-02-23 17:55:21 +00004308 ret = 0;
4309 }
4310 break;
4311 }
4312 if (next->c1 == NULL) break;
4313 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00004314 if ((xmlStrEqual(next->c1->name, name)) &&
4315 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
4316 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004317 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004318 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004319 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004320 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004321 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004322 "Definition of %s has duplicate references to %s:%s\n",
4323 elem->name, cur->prefix, name);
4324 }
Owen Taylor3473f882001-02-23 17:55:21 +00004325 ret = 0;
4326 }
4327 next = next->c2;
4328 }
4329 }
4330 cur = cur->c2;
4331 }
4332 }
4333
4334 /* VC: Unique Element Type Declaration */
4335 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004336 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004337 ((tst->prefix == elem->prefix) ||
4338 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004339 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004340 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4341 "Redefinition of element %s\n",
4342 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004343 ret = 0;
4344 }
4345 tst = xmlGetDtdElementDesc(doc->extSubset, 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 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004355 /* One ID per Element Type
4356 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004357 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4358 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004359 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004360 return(ret);
4361}
4362
4363/**
4364 * xmlValidateOneAttribute:
4365 * @ctxt: the validation context
4366 * @doc: a document instance
4367 * @elem: an element instance
4368 * @attr: an attribute instance
4369 * @value: the attribute value (without entities processing)
4370 *
4371 * Try to validate a single attribute for an element
4372 * basically it does the following checks as described by the
4373 * XML-1.0 recommendation:
4374 * - [ VC: Attribute Value Type ]
4375 * - [ VC: Fixed Attribute Default ]
4376 * - [ VC: Entity Name ]
4377 * - [ VC: Name Token ]
4378 * - [ VC: ID ]
4379 * - [ VC: IDREF ]
4380 * - [ VC: Entity Name ]
4381 * - [ VC: Notation Attributes ]
4382 *
4383 * The ID/IDREF uniqueness and matching are done separately
4384 *
4385 * returns 1 if valid or 0 otherwise
4386 */
4387
4388int
4389xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004390 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4391{
Owen Taylor3473f882001-02-23 17:55:21 +00004392 xmlAttributePtr attrDecl = NULL;
4393 int val;
4394 int ret = 1;
4395
4396 CHECK_DTD;
4397 if ((elem == NULL) || (elem->name == NULL)) return(0);
4398 if ((attr == NULL) || (attr->name == NULL)) return(0);
4399
4400 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004401 xmlChar fn[50];
4402 xmlChar *fullname;
4403
4404 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4405 if (fullname == NULL)
4406 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004407 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004408 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004409 attr->name, attr->ns->prefix);
4410 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004411 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004412 attr->name, attr->ns->prefix);
4413 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004414 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004415 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4416 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004417 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004418 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004419 if ((fullname != fn) && (fullname != elem->name))
4420 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004421 }
4422 if (attrDecl == NULL) {
4423 if (attr->ns != NULL) {
4424 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4425 attr->name, attr->ns->prefix);
4426 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4427 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4428 attr->name, attr->ns->prefix);
4429 } else {
4430 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4431 elem->name, attr->name);
4432 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4433 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4434 elem->name, attr->name);
4435 }
4436 }
4437
4438
4439 /* Validity Constraint: Attribute Value Type */
4440 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004441 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004442 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004443 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004444 return(0);
4445 }
4446 attr->atype = attrDecl->atype;
4447
Daniel Veillardae0765b2008-07-31 19:54:59 +00004448 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
Owen Taylor3473f882001-02-23 17:55:21 +00004449 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004450 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004451 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004452 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004453 ret = 0;
4454 }
4455
4456 /* Validity constraint: Fixed Attribute Default */
4457 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4458 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004459 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004460 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004461 attr->name, elem->name, attrDecl->defaultValue);
4462 ret = 0;
4463 }
4464 }
4465
4466 /* Validity Constraint: ID uniqueness */
4467 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4468 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4469 ret = 0;
4470 }
4471
4472 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4473 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4474 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4475 ret = 0;
4476 }
4477
4478 /* Validity Constraint: Notation Attributes */
4479 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4480 xmlEnumerationPtr tree = attrDecl->tree;
4481 xmlNotationPtr nota;
4482
4483 /* First check that the given NOTATION was declared */
4484 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4485 if (nota == NULL)
4486 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4487
4488 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004489 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004490 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004491 value, attr->name, elem->name);
4492 ret = 0;
4493 }
4494
4495 /* Second, verify that it's among the list */
4496 while (tree != NULL) {
4497 if (xmlStrEqual(tree->name, value)) break;
4498 tree = tree->next;
4499 }
4500 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004501 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004502"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004503 value, attr->name, elem->name);
4504 ret = 0;
4505 }
4506 }
4507
4508 /* Validity Constraint: Enumeration */
4509 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4510 xmlEnumerationPtr tree = attrDecl->tree;
4511 while (tree != NULL) {
4512 if (xmlStrEqual(tree->name, value)) break;
4513 tree = tree->next;
4514 }
4515 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004516 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004517 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004518 value, attr->name, elem->name);
4519 ret = 0;
4520 }
4521 }
4522
4523 /* Fixed Attribute Default */
4524 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4525 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004526 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004527 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004528 attr->name, elem->name, attrDecl->defaultValue);
4529 ret = 0;
4530 }
4531
4532 /* Extra check for the attribute value */
4533 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4534 attrDecl->atype, value);
4535
4536 return(ret);
4537}
4538
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004539/**
4540 * xmlValidateOneNamespace:
4541 * @ctxt: the validation context
4542 * @doc: a document instance
4543 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004544 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004545 * @ns: an namespace declaration instance
4546 * @value: the attribute value (without entities processing)
4547 *
4548 * Try to validate a single namespace declaration for an element
4549 * basically it does the following checks as described by the
4550 * XML-1.0 recommendation:
4551 * - [ VC: Attribute Value Type ]
4552 * - [ VC: Fixed Attribute Default ]
4553 * - [ VC: Entity Name ]
4554 * - [ VC: Name Token ]
4555 * - [ VC: ID ]
4556 * - [ VC: IDREF ]
4557 * - [ VC: Entity Name ]
4558 * - [ VC: Notation Attributes ]
4559 *
4560 * The ID/IDREF uniqueness and matching are done separately
4561 *
4562 * returns 1 if valid or 0 otherwise
4563 */
4564
4565int
4566xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4567xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4568 /* xmlElementPtr elemDecl; */
4569 xmlAttributePtr attrDecl = NULL;
4570 int val;
4571 int ret = 1;
4572
4573 CHECK_DTD;
4574 if ((elem == NULL) || (elem->name == NULL)) return(0);
4575 if ((ns == NULL) || (ns->href == NULL)) return(0);
4576
4577 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004578 xmlChar fn[50];
4579 xmlChar *fullname;
4580
4581 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4582 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004583 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004584 return(0);
4585 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004586 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004587 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004588 ns->prefix, BAD_CAST "xmlns");
4589 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004590 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004591 ns->prefix, BAD_CAST "xmlns");
4592 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004593 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004594 BAD_CAST "xmlns");
4595 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004596 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004597 BAD_CAST "xmlns");
4598 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004599 if ((fullname != fn) && (fullname != elem->name))
4600 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004601 }
4602 if (attrDecl == NULL) {
4603 if (ns->prefix != NULL) {
4604 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4605 ns->prefix, BAD_CAST "xmlns");
4606 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4607 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4608 ns->prefix, BAD_CAST "xmlns");
4609 } else {
4610 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4611 elem->name, BAD_CAST "xmlns");
4612 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4613 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4614 elem->name, BAD_CAST "xmlns");
4615 }
4616 }
4617
4618
4619 /* Validity Constraint: Attribute Value Type */
4620 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004621 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004622 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004623 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004624 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004625 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004626 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004627 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004628 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004629 }
4630 return(0);
4631 }
4632
Daniel Veillardae0765b2008-07-31 19:54:59 +00004633 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004634 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004635 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004636 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004637 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004638 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004639 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004640 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004641 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004642 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004643 }
4644 ret = 0;
4645 }
4646
4647 /* Validity constraint: Fixed Attribute Default */
4648 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4649 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004650 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004651 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004652 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4653 ns->prefix, elem->name, attrDecl->defaultValue);
4654 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004655 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004656 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004657 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004658 }
4659 ret = 0;
4660 }
4661 }
4662
4663 /* Validity Constraint: ID uniqueness */
4664 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4665 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4666 ret = 0;
4667 }
4668
4669 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4670 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4671 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4672 ret = 0;
4673 }
4674
4675 /* Validity Constraint: Notation Attributes */
4676 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4677 xmlEnumerationPtr tree = attrDecl->tree;
4678 xmlNotationPtr nota;
4679
4680 /* First check that the given NOTATION was declared */
4681 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4682 if (nota == NULL)
4683 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4684
4685 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004686 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004687 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004688 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4689 value, ns->prefix, elem->name);
4690 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004691 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004692 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004693 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004694 }
4695 ret = 0;
4696 }
4697
4698 /* Second, verify that it's among the list */
4699 while (tree != NULL) {
4700 if (xmlStrEqual(tree->name, value)) break;
4701 tree = tree->next;
4702 }
4703 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004704 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004705 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004706"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4707 value, ns->prefix, elem->name);
4708 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004709 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004710"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004711 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004712 }
4713 ret = 0;
4714 }
4715 }
4716
4717 /* Validity Constraint: Enumeration */
4718 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4719 xmlEnumerationPtr tree = attrDecl->tree;
4720 while (tree != NULL) {
4721 if (xmlStrEqual(tree->name, value)) break;
4722 tree = tree->next;
4723 }
4724 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004725 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004726 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004727"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4728 value, ns->prefix, elem->name);
4729 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004730 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004731"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004732 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004733 }
4734 ret = 0;
4735 }
4736 }
4737
4738 /* Fixed Attribute Default */
4739 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4740 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004741 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004742 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004743 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4744 ns->prefix, elem->name, attrDecl->defaultValue);
4745 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004746 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004747 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004748 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004749 }
4750 ret = 0;
4751 }
4752
4753 /* Extra check for the attribute value */
4754 if (ns->prefix != NULL) {
4755 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4756 attrDecl->atype, value);
4757 } else {
4758 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4759 attrDecl->atype, value);
4760 }
4761
4762 return(ret);
4763}
4764
Daniel Veillard118aed72002-09-24 14:13:13 +00004765#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004766/**
4767 * xmlValidateSkipIgnorable:
4768 * @ctxt: the validation context
4769 * @child: the child list
4770 *
4771 * Skip ignorable elements w.r.t. the validation process
4772 *
4773 * returns the first element to consider for validation of the content model
4774 */
4775
4776static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004777xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004778 while (child != NULL) {
4779 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004780 /* These things are ignored (skipped) during validation. */
4781 case XML_PI_NODE:
4782 case XML_COMMENT_NODE:
4783 case XML_XINCLUDE_START:
4784 case XML_XINCLUDE_END:
4785 child = child->next;
4786 break;
4787 case XML_TEXT_NODE:
4788 if (xmlIsBlankNode(child))
4789 child = child->next;
4790 else
4791 return(child);
4792 break;
4793 /* keep current node */
4794 default:
4795 return(child);
4796 }
4797 }
4798 return(child);
4799}
4800
4801/**
4802 * xmlValidateElementType:
4803 * @ctxt: the validation context
4804 *
4805 * Try to validate the content model of an element internal function
4806 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004807 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4808 * reference is found and -3 if the validation succeeded but
4809 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004810 */
4811
4812static int
4813xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004814 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004815 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004816
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004817 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004818 if ((NODE == NULL) && (CONT == NULL))
4819 return(1);
4820 if ((NODE == NULL) &&
4821 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4822 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4823 return(1);
4824 }
4825 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004826 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004827 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004828
4829 /*
4830 * We arrive here when more states need to be examined
4831 */
4832cont:
4833
4834 /*
4835 * We just recovered from a rollback generated by a possible
4836 * epsilon transition, go directly to the analysis phase
4837 */
4838 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004839 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004840 DEBUG_VALID_STATE(NODE, CONT)
4841 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004842 goto analyze;
4843 }
4844
4845 DEBUG_VALID_STATE(NODE, CONT)
4846 /*
4847 * we may have to save a backup state here. This is the equivalent
4848 * of handling epsilon transition in NFAs.
4849 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004850 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004851 ((CONT->parent == NULL) ||
4852 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004853 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004854 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004855 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004856 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004857 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4858 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004859 }
4860
4861
4862 /*
4863 * Check first if the content matches
4864 */
4865 switch (CONT->type) {
4866 case XML_ELEMENT_CONTENT_PCDATA:
4867 if (NODE == NULL) {
4868 DEBUG_VALID_MSG("pcdata failed no node");
4869 ret = 0;
4870 break;
4871 }
4872 if (NODE->type == XML_TEXT_NODE) {
4873 DEBUG_VALID_MSG("pcdata found, skip to next");
4874 /*
4875 * go to next element in the content model
4876 * skipping ignorable elems
4877 */
4878 do {
4879 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004880 NODE = xmlValidateSkipIgnorable(NODE);
4881 if ((NODE != NULL) &&
4882 (NODE->type == XML_ENTITY_REF_NODE))
4883 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004884 } while ((NODE != NULL) &&
4885 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004886 (NODE->type != XML_TEXT_NODE) &&
4887 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004888 ret = 1;
4889 break;
4890 } else {
4891 DEBUG_VALID_MSG("pcdata failed");
4892 ret = 0;
4893 break;
4894 }
4895 break;
4896 case XML_ELEMENT_CONTENT_ELEMENT:
4897 if (NODE == NULL) {
4898 DEBUG_VALID_MSG("element failed no node");
4899 ret = 0;
4900 break;
4901 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004902 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4903 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004904 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004905 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4906 ret = (CONT->prefix == NULL);
4907 } else if (CONT->prefix == NULL) {
4908 ret = 0;
4909 } else {
4910 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4911 }
4912 }
4913 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004914 DEBUG_VALID_MSG("element found, skip to next");
4915 /*
4916 * go to next element in the content model
4917 * skipping ignorable elems
4918 */
4919 do {
4920 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004921 NODE = xmlValidateSkipIgnorable(NODE);
4922 if ((NODE != NULL) &&
4923 (NODE->type == XML_ENTITY_REF_NODE))
4924 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004925 } while ((NODE != NULL) &&
4926 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004927 (NODE->type != XML_TEXT_NODE) &&
4928 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004929 } else {
4930 DEBUG_VALID_MSG("element failed");
4931 ret = 0;
4932 break;
4933 }
4934 break;
4935 case XML_ELEMENT_CONTENT_OR:
4936 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004937 * Small optimization.
4938 */
4939 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4940 if ((NODE == NULL) ||
4941 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4942 DEPTH++;
4943 CONT = CONT->c2;
4944 goto cont;
4945 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004946 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4947 ret = (CONT->c1->prefix == NULL);
4948 } else if (CONT->c1->prefix == NULL) {
4949 ret = 0;
4950 } else {
4951 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4952 }
4953 if (ret == 0) {
4954 DEPTH++;
4955 CONT = CONT->c2;
4956 goto cont;
4957 }
Daniel Veillard85349052001-04-20 13:48:21 +00004958 }
4959
4960 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004961 * save the second branch 'or' branch
4962 */
4963 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004964 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4965 OCCURS, ROLLBACK_OR) < 0)
4966 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004967 DEPTH++;
4968 CONT = CONT->c1;
4969 goto cont;
4970 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004971 /*
4972 * Small optimization.
4973 */
4974 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4975 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4976 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4977 if ((NODE == NULL) ||
4978 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4979 DEPTH++;
4980 CONT = CONT->c2;
4981 goto cont;
4982 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004983 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4984 ret = (CONT->c1->prefix == NULL);
4985 } else if (CONT->c1->prefix == NULL) {
4986 ret = 0;
4987 } else {
4988 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4989 }
4990 if (ret == 0) {
4991 DEPTH++;
4992 CONT = CONT->c2;
4993 goto cont;
4994 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004995 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004996 DEPTH++;
4997 CONT = CONT->c1;
4998 goto cont;
4999 }
5000
5001 /*
5002 * At this point handle going up in the tree
5003 */
5004 if (ret == -1) {
5005 DEBUG_VALID_MSG("error found returning");
5006 return(ret);
5007 }
5008analyze:
5009 while (CONT != NULL) {
5010 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005011 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005012 * this level.
5013 */
5014 if (ret == 0) {
5015 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005016 xmlNodePtr cur;
5017
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005018 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005019 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005020 DEBUG_VALID_MSG("Once branch failed, rollback");
5021 if (vstateVPop(ctxt) < 0 ) {
5022 DEBUG_VALID_MSG("exhaustion, failed");
5023 return(0);
5024 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005025 if (cur != ctxt->vstate->node)
5026 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005027 goto cont;
5028 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00005029 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005030 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005031 DEBUG_VALID_MSG("Plus branch failed, rollback");
5032 if (vstateVPop(ctxt) < 0 ) {
5033 DEBUG_VALID_MSG("exhaustion, failed");
5034 return(0);
5035 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005036 if (cur != ctxt->vstate->node)
5037 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005038 goto cont;
5039 }
5040 DEBUG_VALID_MSG("Plus branch found");
5041 ret = 1;
5042 break;
5043 case XML_ELEMENT_CONTENT_MULT:
5044#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00005045 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005046 DEBUG_VALID_MSG("Mult branch failed");
5047 } else {
5048 DEBUG_VALID_MSG("Mult branch found");
5049 }
5050#endif
5051 ret = 1;
5052 break;
5053 case XML_ELEMENT_CONTENT_OPT:
5054 DEBUG_VALID_MSG("Option branch failed");
5055 ret = 1;
5056 break;
5057 }
5058 } else {
5059 switch (CONT->ocur) {
5060 case XML_ELEMENT_CONTENT_OPT:
5061 DEBUG_VALID_MSG("Option branch succeeded");
5062 ret = 1;
5063 break;
5064 case XML_ELEMENT_CONTENT_ONCE:
5065 DEBUG_VALID_MSG("Once branch succeeded");
5066 ret = 1;
5067 break;
5068 case XML_ELEMENT_CONTENT_PLUS:
5069 if (STATE == ROLLBACK_PARENT) {
5070 DEBUG_VALID_MSG("Plus branch rollback");
5071 ret = 1;
5072 break;
5073 }
5074 if (NODE == NULL) {
5075 DEBUG_VALID_MSG("Plus branch exhausted");
5076 ret = 1;
5077 break;
5078 }
5079 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00005080 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005081 goto cont;
5082 case XML_ELEMENT_CONTENT_MULT:
5083 if (STATE == ROLLBACK_PARENT) {
5084 DEBUG_VALID_MSG("Mult branch rollback");
5085 ret = 1;
5086 break;
5087 }
5088 if (NODE == NULL) {
5089 DEBUG_VALID_MSG("Mult branch exhausted");
5090 ret = 1;
5091 break;
5092 }
5093 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00005094 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005095 goto cont;
5096 }
5097 }
5098 STATE = 0;
5099
5100 /*
5101 * Then act accordingly at the parent level
5102 */
Daniel Veillard5344c602001-12-31 16:37:34 +00005103 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005104 if (CONT->parent == NULL)
5105 break;
5106
5107 switch (CONT->parent->type) {
5108 case XML_ELEMENT_CONTENT_PCDATA:
5109 DEBUG_VALID_MSG("Error: parent pcdata");
5110 return(-1);
5111 case XML_ELEMENT_CONTENT_ELEMENT:
5112 DEBUG_VALID_MSG("Error: parent element");
5113 return(-1);
5114 case XML_ELEMENT_CONTENT_OR:
5115 if (ret == 1) {
5116 DEBUG_VALID_MSG("Or succeeded");
5117 CONT = CONT->parent;
5118 DEPTH--;
5119 } else {
5120 DEBUG_VALID_MSG("Or failed");
5121 CONT = CONT->parent;
5122 DEPTH--;
5123 }
5124 break;
5125 case XML_ELEMENT_CONTENT_SEQ:
5126 if (ret == 0) {
5127 DEBUG_VALID_MSG("Sequence failed");
5128 CONT = CONT->parent;
5129 DEPTH--;
5130 } else if (CONT == CONT->parent->c1) {
5131 DEBUG_VALID_MSG("Sequence testing 2nd branch");
5132 CONT = CONT->parent->c2;
5133 goto cont;
5134 } else {
5135 DEBUG_VALID_MSG("Sequence succeeded");
5136 CONT = CONT->parent;
5137 DEPTH--;
5138 }
5139 }
5140 }
5141 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005142 xmlNodePtr cur;
5143
5144 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005145 DEBUG_VALID_MSG("Failed, remaining input, rollback");
5146 if (vstateVPop(ctxt) < 0 ) {
5147 DEBUG_VALID_MSG("exhaustion, failed");
5148 return(0);
5149 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005150 if (cur != ctxt->vstate->node)
5151 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005152 goto cont;
5153 }
5154 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005155 xmlNodePtr cur;
5156
5157 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005158 DEBUG_VALID_MSG("Failure, rollback");
5159 if (vstateVPop(ctxt) < 0 ) {
5160 DEBUG_VALID_MSG("exhaustion, failed");
5161 return(0);
5162 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005163 if (cur != ctxt->vstate->node)
5164 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005165 goto cont;
5166 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005167 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005168}
Daniel Veillard23e73572002-09-19 19:56:43 +00005169#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005170
5171/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00005172 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005173 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00005174 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005175 * @content: An element
5176 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5177 *
5178 * This will dump the list of elements to the buffer
5179 * Intended just for the debug routine
5180 */
5181static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00005182xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005183 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00005184 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005185
5186 if (node == NULL) return;
5187 if (glob) strcat(buf, "(");
5188 cur = node;
5189 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005190 len = strlen(buf);
5191 if (size - len < 50) {
5192 if ((size - len > 4) && (buf[len - 1] != '.'))
5193 strcat(buf, " ...");
5194 return;
5195 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005196 switch (cur->type) {
5197 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005198 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005199 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005200 if ((size - len > 4) && (buf[len - 1] != '.'))
5201 strcat(buf, " ...");
5202 return;
5203 }
5204 strcat(buf, (char *) cur->ns->prefix);
5205 strcat(buf, ":");
5206 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005207 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005208 if ((size - len > 4) && (buf[len - 1] != '.'))
5209 strcat(buf, " ...");
5210 return;
5211 }
5212 strcat(buf, (char *) cur->name);
5213 if (cur->next != NULL)
5214 strcat(buf, " ");
5215 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005216 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005217 if (xmlIsBlankNode(cur))
5218 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005219 case XML_CDATA_SECTION_NODE:
5220 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005221 strcat(buf, "CDATA");
5222 if (cur->next != NULL)
5223 strcat(buf, " ");
5224 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005225 case XML_ATTRIBUTE_NODE:
5226 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005227#ifdef LIBXML_DOCB_ENABLED
5228 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005229#endif
5230 case XML_HTML_DOCUMENT_NODE:
5231 case XML_DOCUMENT_TYPE_NODE:
5232 case XML_DOCUMENT_FRAG_NODE:
5233 case XML_NOTATION_NODE:
5234 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005235 strcat(buf, "???");
5236 if (cur->next != NULL)
5237 strcat(buf, " ");
5238 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005239 case XML_ENTITY_NODE:
5240 case XML_PI_NODE:
5241 case XML_DTD_NODE:
5242 case XML_COMMENT_NODE:
5243 case XML_ELEMENT_DECL:
5244 case XML_ATTRIBUTE_DECL:
5245 case XML_ENTITY_DECL:
5246 case XML_XINCLUDE_START:
5247 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005248 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005249 }
5250 cur = cur->next;
5251 }
5252 if (glob) strcat(buf, ")");
5253}
5254
5255/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005256 * xmlValidateElementContent:
5257 * @ctxt: the validation context
5258 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005259 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005260 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005261 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005262 *
5263 * Try to validate the content model of an element
5264 *
5265 * returns 1 if valid or 0 if not and -1 in case of error
5266 */
5267
5268static int
5269xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005270 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00005271 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00005272#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00005273 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00005274#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00005275 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005276 xmlElementContentPtr cont;
5277 const xmlChar *name;
5278
5279 if (elemDecl == NULL)
5280 return(-1);
5281 cont = elemDecl->content;
5282 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005283
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005284#ifdef LIBXML_REGEXP_ENABLED
5285 /* Build the regexp associated to the content model */
5286 if (elemDecl->contModel == NULL)
5287 ret = xmlValidBuildContentModel(ctxt, elemDecl);
5288 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005289 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005290 } else {
5291 xmlRegExecCtxtPtr exec;
5292
Daniel Veillardec498e12003-02-05 11:01:50 +00005293 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5294 return(-1);
5295 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005296 ctxt->nodeMax = 0;
5297 ctxt->nodeNr = 0;
5298 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005299 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5300 if (exec != NULL) {
5301 cur = child;
5302 while (cur != NULL) {
5303 switch (cur->type) {
5304 case XML_ENTITY_REF_NODE:
5305 /*
5306 * Push the current node to be able to roll back
5307 * and process within the entity
5308 */
5309 if ((cur->children != NULL) &&
5310 (cur->children->children != NULL)) {
5311 nodeVPush(ctxt, cur);
5312 cur = cur->children->children;
5313 continue;
5314 }
5315 break;
5316 case XML_TEXT_NODE:
5317 if (xmlIsBlankNode(cur))
5318 break;
5319 ret = 0;
5320 goto fail;
5321 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00005322 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005323 ret = 0;
5324 goto fail;
5325 case XML_ELEMENT_NODE:
5326 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005327 xmlChar fn[50];
5328 xmlChar *fullname;
5329
5330 fullname = xmlBuildQName(cur->name,
5331 cur->ns->prefix, fn, 50);
5332 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005333 ret = -1;
5334 goto fail;
5335 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005336 ret = xmlRegExecPushString(exec, fullname, NULL);
5337 if ((fullname != fn) && (fullname != cur->name))
5338 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005339 } else {
5340 ret = xmlRegExecPushString(exec, cur->name, NULL);
5341 }
5342 break;
5343 default:
5344 break;
5345 }
5346 /*
5347 * Switch to next element
5348 */
5349 cur = cur->next;
5350 while (cur == NULL) {
5351 cur = nodeVPop(ctxt);
5352 if (cur == NULL)
5353 break;
5354 cur = cur->next;
5355 }
5356 }
5357 ret = xmlRegExecPushString(exec, NULL, NULL);
5358fail:
5359 xmlRegFreeExecCtxt(exec);
5360 }
5361 }
5362#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005363 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005364 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005365 */
5366 ctxt->vstateMax = 8;
5367 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5368 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5369 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005370 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005371 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005372 }
5373 /*
5374 * The first entry in the stack is reserved to the current state
5375 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005376 ctxt->nodeMax = 0;
5377 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005378 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005379 ctxt->vstate = &ctxt->vstateTab[0];
5380 ctxt->vstateNr = 1;
5381 CONT = cont;
5382 NODE = child;
5383 DEPTH = 0;
5384 OCCURS = 0;
5385 STATE = 0;
5386 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005387 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005388 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5389 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005390 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005391 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005392 /*
5393 * An entities reference appeared at this level.
5394 * Buid a minimal representation of this node content
5395 * sufficient to run the validation process on it
5396 */
5397 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005398 cur = child;
5399 while (cur != NULL) {
5400 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005401 case XML_ENTITY_REF_NODE:
5402 /*
5403 * Push the current node to be able to roll back
5404 * and process within the entity
5405 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005406 if ((cur->children != NULL) &&
5407 (cur->children->children != NULL)) {
5408 nodeVPush(ctxt, cur);
5409 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005410 continue;
5411 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005412 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005413 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005414 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005415 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005416 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005417 case XML_CDATA_SECTION_NODE:
5418 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005419 case XML_ELEMENT_NODE:
5420 /*
5421 * Allocate a new node and minimally fills in
5422 * what's required
5423 */
5424 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5425 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005426 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005427 xmlFreeNodeList(repl);
5428 ret = -1;
5429 goto done;
5430 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005431 tmp->type = cur->type;
5432 tmp->name = cur->name;
5433 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005434 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005435 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005436 if (repl == NULL)
5437 repl = last = tmp;
5438 else {
5439 last->next = tmp;
5440 last = tmp;
5441 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005442 if (cur->type == XML_CDATA_SECTION_NODE) {
5443 /*
5444 * E59 spaces in CDATA does not match the
5445 * nonterminal S
5446 */
5447 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5448 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005449 break;
5450 default:
5451 break;
5452 }
5453 /*
5454 * Switch to next element
5455 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005456 cur = cur->next;
5457 while (cur == NULL) {
5458 cur = nodeVPop(ctxt);
5459 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005460 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005461 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005462 }
5463 }
5464
5465 /*
5466 * Relaunch the validation
5467 */
5468 ctxt->vstate = &ctxt->vstateTab[0];
5469 ctxt->vstateNr = 1;
5470 CONT = cont;
5471 NODE = repl;
5472 DEPTH = 0;
5473 OCCURS = 0;
5474 STATE = 0;
5475 ret = xmlValidateElementType(ctxt);
5476 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005477#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005478 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00005479 if (ctxt != NULL) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005480 char expr[5000];
5481 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005482
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005483 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005484 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005485 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005486#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005487 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005488 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005489 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005490#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005491 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005492
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005493 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005494 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5495 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5496 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005497 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005498 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5499 "Element content does not follow the DTD, expecting %s, got %s\n",
5500 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005501 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005502 } else {
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,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005505 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005506 name, NULL, NULL);
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\n",
5510 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005511 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005512 }
5513 ret = 0;
5514 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005515 if (ret == -3)
5516 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005517
Daniel Veillard23e73572002-09-19 19:56:43 +00005518#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005519done:
5520 /*
5521 * Deallocate the copy if done, and free up the validation stack
5522 */
5523 while (repl != NULL) {
5524 tmp = repl->next;
5525 xmlFree(repl);
5526 repl = tmp;
5527 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005528 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005529 if (ctxt->vstateTab != NULL) {
5530 xmlFree(ctxt->vstateTab);
5531 ctxt->vstateTab = NULL;
5532 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005533#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005534 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005535 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005536 if (ctxt->nodeTab != NULL) {
5537 xmlFree(ctxt->nodeTab);
5538 ctxt->nodeTab = NULL;
5539 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005540 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005541
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005542}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005543
Owen Taylor3473f882001-02-23 17:55:21 +00005544/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005545 * xmlValidateCdataElement:
5546 * @ctxt: the validation context
5547 * @doc: a document instance
5548 * @elem: an element instance
5549 *
5550 * Check that an element follows #CDATA
5551 *
5552 * returns 1 if valid or 0 otherwise
5553 */
5554static int
5555xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5556 xmlNodePtr elem) {
5557 int ret = 1;
5558 xmlNodePtr cur, child;
5559
Daniel Veillardceb09b92002-10-04 11:46:37 +00005560 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005561 return(0);
5562
5563 child = elem->children;
5564
5565 cur = child;
5566 while (cur != NULL) {
5567 switch (cur->type) {
5568 case XML_ENTITY_REF_NODE:
5569 /*
5570 * Push the current node to be able to roll back
5571 * and process within the entity
5572 */
5573 if ((cur->children != NULL) &&
5574 (cur->children->children != NULL)) {
5575 nodeVPush(ctxt, cur);
5576 cur = cur->children->children;
5577 continue;
5578 }
5579 break;
5580 case XML_COMMENT_NODE:
5581 case XML_PI_NODE:
5582 case XML_TEXT_NODE:
5583 case XML_CDATA_SECTION_NODE:
5584 break;
5585 default:
5586 ret = 0;
5587 goto done;
5588 }
5589 /*
5590 * Switch to next element
5591 */
5592 cur = cur->next;
5593 while (cur == NULL) {
5594 cur = nodeVPop(ctxt);
5595 if (cur == NULL)
5596 break;
5597 cur = cur->next;
5598 }
5599 }
5600done:
5601 ctxt->nodeMax = 0;
5602 ctxt->nodeNr = 0;
5603 if (ctxt->nodeTab != NULL) {
5604 xmlFree(ctxt->nodeTab);
5605 ctxt->nodeTab = NULL;
5606 }
5607 return(ret);
5608}
5609
5610/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005611 * xmlValidateCheckMixed:
5612 * @ctxt: the validation context
5613 * @cont: the mixed content model
5614 * @qname: the qualified name as appearing in the serialization
5615 *
5616 * Check if the given node is part of the content model.
5617 *
5618 * Returns 1 if yes, 0 if no, -1 in case of error
5619 */
5620static int
William M. Brackedb65a72004-02-06 07:36:04 +00005621xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005622 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005623 const xmlChar *name;
5624 int plen;
5625 name = xmlSplitQName3(qname, &plen);
5626
5627 if (name == NULL) {
5628 while (cont != NULL) {
5629 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5630 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5631 return(1);
5632 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5633 (cont->c1 != NULL) &&
5634 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5635 if ((cont->c1->prefix == NULL) &&
5636 (xmlStrEqual(cont->c1->name, qname)))
5637 return(1);
5638 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5639 (cont->c1 == NULL) ||
5640 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005641 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5642 "Internal: MIXED struct corrupted\n",
5643 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005644 break;
5645 }
5646 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005647 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005648 } else {
5649 while (cont != NULL) {
5650 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5651 if ((cont->prefix != NULL) &&
5652 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5653 (xmlStrEqual(cont->name, name)))
5654 return(1);
5655 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5656 (cont->c1 != NULL) &&
5657 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5658 if ((cont->c1->prefix != NULL) &&
5659 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5660 (xmlStrEqual(cont->c1->name, name)))
5661 return(1);
5662 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5663 (cont->c1 == NULL) ||
5664 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005665 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5666 "Internal: MIXED struct corrupted\n",
5667 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005668 break;
5669 }
5670 cont = cont->c2;
5671 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005672 }
5673 return(0);
5674}
5675
5676/**
5677 * xmlValidGetElemDecl:
5678 * @ctxt: the validation context
5679 * @doc: a document instance
5680 * @elem: an element instance
5681 * @extsubset: pointer, (out) indicate if the declaration was found
5682 * in the external subset.
5683 *
5684 * Finds a declaration associated to an element in the document.
5685 *
5686 * returns the pointer to the declaration or NULL if not found.
5687 */
5688static xmlElementPtr
5689xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5690 xmlNodePtr elem, int *extsubset) {
5691 xmlElementPtr elemDecl = NULL;
5692 const xmlChar *prefix = NULL;
5693
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005694 if ((ctxt == NULL) || (doc == NULL) ||
5695 (elem == NULL) || (elem->name == NULL))
5696 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005697 if (extsubset != NULL)
5698 *extsubset = 0;
5699
5700 /*
5701 * Fetch the declaration for the qualified name
5702 */
5703 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5704 prefix = elem->ns->prefix;
5705
5706 if (prefix != NULL) {
5707 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5708 elem->name, prefix);
5709 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5710 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5711 elem->name, prefix);
5712 if ((elemDecl != NULL) && (extsubset != NULL))
5713 *extsubset = 1;
5714 }
5715 }
5716
5717 /*
5718 * Fetch the declaration for the non qualified name
5719 * This is "non-strict" validation should be done on the
5720 * full QName but in that case being flexible makes sense.
5721 */
5722 if (elemDecl == NULL) {
5723 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5724 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5725 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5726 if ((elemDecl != NULL) && (extsubset != NULL))
5727 *extsubset = 1;
5728 }
5729 }
5730 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005731 xmlErrValidNode(ctxt, elem,
5732 XML_DTD_UNKNOWN_ELEM,
5733 "No declaration for element %s\n",
5734 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005735 }
5736 return(elemDecl);
5737}
5738
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005739#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005740/**
5741 * xmlValidatePushElement:
5742 * @ctxt: the validation context
5743 * @doc: a document instance
5744 * @elem: an element instance
5745 * @qname: the qualified name as appearing in the serialization
5746 *
5747 * Push a new element start on the validation stack.
5748 *
5749 * returns 1 if no validation problem was found or 0 otherwise
5750 */
5751int
5752xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5753 xmlNodePtr elem, const xmlChar *qname) {
5754 int ret = 1;
5755 xmlElementPtr eDecl;
5756 int extsubset = 0;
5757
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005758 if (ctxt == NULL)
5759 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005760/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005761 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5762 xmlValidStatePtr state = ctxt->vstate;
5763 xmlElementPtr elemDecl;
5764
5765 /*
5766 * Check the new element agaisnt the content model of the new elem.
5767 */
5768 if (state->elemDecl != NULL) {
5769 elemDecl = state->elemDecl;
5770
5771 switch(elemDecl->etype) {
5772 case XML_ELEMENT_TYPE_UNDEFINED:
5773 ret = 0;
5774 break;
5775 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005776 xmlErrValidNode(ctxt, state->node,
5777 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005778 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005779 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005780 ret = 0;
5781 break;
5782 case XML_ELEMENT_TYPE_ANY:
5783 /* I don't think anything is required then */
5784 break;
5785 case XML_ELEMENT_TYPE_MIXED:
5786 /* simple case of declared as #PCDATA */
5787 if ((elemDecl->content != NULL) &&
5788 (elemDecl->content->type ==
5789 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005790 xmlErrValidNode(ctxt, state->node,
5791 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005792 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005793 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005794 ret = 0;
5795 } else {
5796 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5797 qname);
5798 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005799 xmlErrValidNode(ctxt, state->node,
5800 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005801 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005802 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005803 }
5804 }
5805 break;
5806 case XML_ELEMENT_TYPE_ELEMENT:
5807 /*
5808 * TODO:
5809 * VC: Standalone Document Declaration
5810 * - element types with element content, if white space
5811 * occurs directly within any instance of those types.
5812 */
5813 if (state->exec != NULL) {
5814 ret = xmlRegExecPushString(state->exec, qname, NULL);
5815 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005816 xmlErrValidNode(ctxt, state->node,
5817 XML_DTD_CONTENT_MODEL,
5818 "Element %s content does not follow the DTD, Misplaced %s\n",
5819 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005820 ret = 0;
5821 } else {
5822 ret = 1;
5823 }
5824 }
5825 break;
5826 }
5827 }
5828 }
5829 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5830 vstateVPush(ctxt, eDecl, elem);
5831 return(ret);
5832}
5833
5834/**
5835 * xmlValidatePushCData:
5836 * @ctxt: the validation context
5837 * @data: some character data read
5838 * @len: the lenght of the data
5839 *
5840 * check the CData parsed for validation in the current stack
5841 *
5842 * returns 1 if no validation problem was found or 0 otherwise
5843 */
5844int
5845xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5846 int ret = 1;
5847
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005848/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005849 if (ctxt == NULL)
5850 return(0);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005851 if (len <= 0)
5852 return(ret);
5853 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5854 xmlValidStatePtr state = ctxt->vstate;
5855 xmlElementPtr elemDecl;
5856
5857 /*
5858 * Check the new element agaisnt the content model of the new elem.
5859 */
5860 if (state->elemDecl != NULL) {
5861 elemDecl = state->elemDecl;
5862
5863 switch(elemDecl->etype) {
5864 case XML_ELEMENT_TYPE_UNDEFINED:
5865 ret = 0;
5866 break;
5867 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005868 xmlErrValidNode(ctxt, state->node,
5869 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005870 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005871 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005872 ret = 0;
5873 break;
5874 case XML_ELEMENT_TYPE_ANY:
5875 break;
5876 case XML_ELEMENT_TYPE_MIXED:
5877 break;
5878 case XML_ELEMENT_TYPE_ELEMENT:
5879 if (len > 0) {
5880 int i;
5881
5882 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005883 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005884 xmlErrValidNode(ctxt, state->node,
5885 XML_DTD_CONTENT_MODEL,
5886 "Element %s content does not follow the DTD, Text not allowed\n",
5887 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005888 ret = 0;
5889 goto done;
5890 }
5891 }
5892 /*
5893 * TODO:
5894 * VC: Standalone Document Declaration
5895 * element types with element content, if white space
5896 * occurs directly within any instance of those types.
5897 */
5898 }
5899 break;
5900 }
5901 }
5902 }
5903done:
5904 return(ret);
5905}
5906
5907/**
5908 * xmlValidatePopElement:
5909 * @ctxt: the validation context
5910 * @doc: a document instance
5911 * @elem: an element instance
5912 * @qname: the qualified name as appearing in the serialization
5913 *
5914 * Pop the element end from the validation stack.
5915 *
5916 * returns 1 if no validation problem was found or 0 otherwise
5917 */
5918int
5919xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005920 xmlNodePtr elem ATTRIBUTE_UNUSED,
5921 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005922 int ret = 1;
5923
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005924 if (ctxt == NULL)
5925 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005926/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005927 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5928 xmlValidStatePtr state = ctxt->vstate;
5929 xmlElementPtr elemDecl;
5930
5931 /*
5932 * Check the new element agaisnt the content model of the new elem.
5933 */
5934 if (state->elemDecl != NULL) {
5935 elemDecl = state->elemDecl;
5936
5937 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5938 if (state->exec != NULL) {
5939 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5940 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005941 xmlErrValidNode(ctxt, state->node,
5942 XML_DTD_CONTENT_MODEL,
5943 "Element %s content does not follow the DTD, Expecting more child\n",
5944 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005945 } else {
5946 /*
5947 * previous validation errors should not generate
5948 * a new one here
5949 */
5950 ret = 1;
5951 }
5952 }
5953 }
5954 }
5955 vstateVPop(ctxt);
5956 }
5957 return(ret);
5958}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005959#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005960
5961/**
Owen Taylor3473f882001-02-23 17:55:21 +00005962 * xmlValidateOneElement:
5963 * @ctxt: the validation context
5964 * @doc: a document instance
5965 * @elem: an element instance
5966 *
5967 * Try to validate a single element and it's attributes,
5968 * basically it does the following checks as described by the
5969 * XML-1.0 recommendation:
5970 * - [ VC: Element Valid ]
5971 * - [ VC: Required Attribute ]
5972 * Then call xmlValidateOneAttribute() for each attribute present.
5973 *
5974 * The ID/IDREF checkings are done separately
5975 *
5976 * returns 1 if valid or 0 otherwise
5977 */
5978
5979int
5980xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5981 xmlNodePtr elem) {
5982 xmlElementPtr elemDecl = NULL;
5983 xmlElementContentPtr cont;
5984 xmlAttributePtr attr;
5985 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005986 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005987 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005988 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005989
5990 CHECK_DTD;
5991
5992 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005993 switch (elem->type) {
5994 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005995 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5996 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005997 return(0);
5998 case XML_TEXT_NODE:
5999 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006000 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6001 "Text element has children !\n",
6002 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006003 return(0);
6004 }
Owen Taylor3473f882001-02-23 17:55:21 +00006005 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006006 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6007 "Text element has namespace !\n",
6008 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006009 return(0);
6010 }
Owen Taylor3473f882001-02-23 17:55:21 +00006011 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006012 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6013 "Text element has no content !\n",
6014 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006015 return(0);
6016 }
6017 return(1);
6018 case XML_XINCLUDE_START:
6019 case XML_XINCLUDE_END:
6020 return(1);
6021 case XML_CDATA_SECTION_NODE:
6022 case XML_ENTITY_REF_NODE:
6023 case XML_PI_NODE:
6024 case XML_COMMENT_NODE:
6025 return(1);
6026 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006027 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6028 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006029 return(0);
6030 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006031 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6032 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006033 return(0);
6034 case XML_DOCUMENT_NODE:
6035 case XML_DOCUMENT_TYPE_NODE:
6036 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006037 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6038 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006039 return(0);
6040 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006041 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6042 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006043 return(0);
6044 case XML_ELEMENT_NODE:
6045 break;
6046 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006047 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6048 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006049 return(0);
6050 }
Owen Taylor3473f882001-02-23 17:55:21 +00006051
6052 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00006053 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00006054 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00006055 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
6056 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006057 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006058
Daniel Veillardea7751d2002-12-20 00:16:24 +00006059 /*
6060 * If vstateNr is not zero that means continuous validation is
6061 * activated, do not try to check the content model at that level.
6062 */
6063 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006064 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00006065 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00006066 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006067 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
6068 "No declaration for element %s\n",
6069 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00006070 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006071 case XML_ELEMENT_TYPE_EMPTY:
6072 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006073 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00006074 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006075 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006076 ret = 0;
6077 }
6078 break;
6079 case XML_ELEMENT_TYPE_ANY:
6080 /* I don't think anything is required then */
6081 break;
6082 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006083
Daniel Veillard04e2dae2001-07-09 20:07:25 +00006084 /* simple case of declared as #PCDATA */
6085 if ((elemDecl->content != NULL) &&
6086 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
6087 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
6088 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006089 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00006090 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006091 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00006092 }
6093 break;
6094 }
Owen Taylor3473f882001-02-23 17:55:21 +00006095 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00006096 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00006097 while (child != NULL) {
6098 if (child->type == XML_ELEMENT_NODE) {
6099 name = child->name;
6100 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006101 xmlChar fn[50];
6102 xmlChar *fullname;
6103
6104 fullname = xmlBuildQName(child->name, child->ns->prefix,
6105 fn, 50);
6106 if (fullname == NULL)
6107 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006108 cont = elemDecl->content;
6109 while (cont != NULL) {
6110 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006111 if (xmlStrEqual(cont->name, fullname))
6112 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006113 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6114 (cont->c1 != NULL) &&
6115 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00006116 if (xmlStrEqual(cont->c1->name, fullname))
6117 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006118 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6119 (cont->c1 == NULL) ||
6120 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006121 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
6122 "Internal: MIXED struct corrupted\n",
6123 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006124 break;
6125 }
6126 cont = cont->c2;
6127 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00006128 if ((fullname != fn) && (fullname != child->name))
6129 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00006130 if (cont != NULL)
6131 goto child_ok;
6132 }
6133 cont = elemDecl->content;
6134 while (cont != NULL) {
6135 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6136 if (xmlStrEqual(cont->name, name)) break;
6137 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6138 (cont->c1 != NULL) &&
6139 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
6140 if (xmlStrEqual(cont->c1->name, name)) break;
6141 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6142 (cont->c1 == NULL) ||
6143 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006144 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
6145 "Internal: MIXED struct corrupted\n",
6146 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006147 break;
6148 }
6149 cont = cont->c2;
6150 }
6151 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006152 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006153 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006154 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006155 ret = 0;
6156 }
6157 }
6158child_ok:
6159 child = child->next;
6160 }
6161 break;
6162 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006163 if ((doc->standalone == 1) && (extsubset == 1)) {
6164 /*
6165 * VC: Standalone Document Declaration
6166 * - element types with element content, if white space
6167 * occurs directly within any instance of those types.
6168 */
6169 child = elem->children;
6170 while (child != NULL) {
6171 if (child->type == XML_TEXT_NODE) {
6172 const xmlChar *content = child->content;
6173
William M. Brack76e95df2003-10-18 16:20:14 +00006174 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006175 content++;
6176 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006177 xmlErrValidNode(ctxt, elem,
6178 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006179"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006180 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006181 ret = 0;
6182 break;
6183 }
6184 }
6185 child =child->next;
6186 }
6187 }
Owen Taylor3473f882001-02-23 17:55:21 +00006188 child = elem->children;
6189 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00006190 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006191 if (tmp <= 0)
6192 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006193 break;
6194 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00006195 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00006196
6197 /* [ VC: Required Attribute ] */
6198 attr = elemDecl->attributes;
6199 while (attr != NULL) {
6200 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006201 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006202
Daniel Veillarde4301c82002-02-13 13:32:35 +00006203 if ((attr->prefix == NULL) &&
6204 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6205 xmlNsPtr ns;
6206
6207 ns = elem->nsDef;
6208 while (ns != NULL) {
6209 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006210 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006211 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006212 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006213 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6214 xmlNsPtr ns;
6215
6216 ns = elem->nsDef;
6217 while (ns != NULL) {
6218 if (xmlStrEqual(attr->name, ns->prefix))
6219 goto found;
6220 ns = ns->next;
6221 }
6222 } else {
6223 xmlAttrPtr attrib;
6224
6225 attrib = elem->properties;
6226 while (attrib != NULL) {
6227 if (xmlStrEqual(attrib->name, attr->name)) {
6228 if (attr->prefix != NULL) {
6229 xmlNsPtr nameSpace = attrib->ns;
6230
6231 if (nameSpace == NULL)
6232 nameSpace = elem->ns;
6233 /*
6234 * qualified names handling is problematic, having a
6235 * different prefix should be possible but DTDs don't
6236 * allow to define the URI instead of the prefix :-(
6237 */
6238 if (nameSpace == NULL) {
6239 if (qualified < 0)
6240 qualified = 0;
6241 } else if (!xmlStrEqual(nameSpace->prefix,
6242 attr->prefix)) {
6243 if (qualified < 1)
6244 qualified = 1;
6245 } else
6246 goto found;
6247 } else {
6248 /*
6249 * We should allow applications to define namespaces
6250 * for their application even if the DTD doesn't
6251 * carry one, otherwise, basically we would always
6252 * break.
6253 */
6254 goto found;
6255 }
6256 }
6257 attrib = attrib->next;
6258 }
Owen Taylor3473f882001-02-23 17:55:21 +00006259 }
6260 if (qualified == -1) {
6261 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006262 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006263 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006264 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006265 ret = 0;
6266 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006267 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006268 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00006269 elem->name, attr->prefix,attr->name);
6270 ret = 0;
6271 }
6272 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006273 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006274 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006275 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006276 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006277 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006278 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006279 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006280 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006281 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
6282 /*
6283 * Special tests checking #FIXED namespace declarations
6284 * have the right value since this is not done as an
6285 * attribute checking
6286 */
6287 if ((attr->prefix == NULL) &&
6288 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6289 xmlNsPtr ns;
6290
6291 ns = elem->nsDef;
6292 while (ns != NULL) {
6293 if (ns->prefix == NULL) {
6294 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006295 xmlErrValidNode(ctxt, elem,
6296 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00006297 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006298 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006299 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006300 }
6301 goto found;
6302 }
6303 ns = ns->next;
6304 }
6305 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6306 xmlNsPtr ns;
6307
6308 ns = elem->nsDef;
6309 while (ns != NULL) {
6310 if (xmlStrEqual(attr->name, ns->prefix)) {
6311 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006312 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006313 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006314 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006315 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006316 }
6317 goto found;
6318 }
6319 ns = ns->next;
6320 }
6321 }
Owen Taylor3473f882001-02-23 17:55:21 +00006322 }
6323found:
6324 attr = attr->nexth;
6325 }
6326 return(ret);
6327}
6328
6329/**
6330 * xmlValidateRoot:
6331 * @ctxt: the validation context
6332 * @doc: a document instance
6333 *
6334 * Try to validate a the root element
6335 * basically it does the following check as described by the
6336 * XML-1.0 recommendation:
6337 * - [ VC: Root Element Type ]
6338 * it doesn't try to recurse or apply other check to the element
6339 *
6340 * returns 1 if valid or 0 otherwise
6341 */
6342
6343int
6344xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6345 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006346 int ret;
6347
Owen Taylor3473f882001-02-23 17:55:21 +00006348 if (doc == NULL) return(0);
6349
6350 root = xmlDocGetRootElement(doc);
6351 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006352 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6353 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006354 return(0);
6355 }
6356
6357 /*
6358 * When doing post validation against a separate DTD, those may
6359 * no internal subset has been generated
6360 */
6361 if ((doc->intSubset != NULL) &&
6362 (doc->intSubset->name != NULL)) {
6363 /*
6364 * Check first the document root against the NQName
6365 */
6366 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6367 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006368 xmlChar fn[50];
6369 xmlChar *fullname;
6370
6371 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6372 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006373 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006374 return(0);
6375 }
6376 ret = xmlStrEqual(doc->intSubset->name, fullname);
6377 if ((fullname != fn) && (fullname != root->name))
6378 xmlFree(fullname);
6379 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006380 goto name_ok;
6381 }
6382 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6383 (xmlStrEqual(root->name, BAD_CAST "html")))
6384 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006385 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6386 "root and DTD name do not match '%s' and '%s'\n",
6387 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006388 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006389 }
6390 }
6391name_ok:
6392 return(1);
6393}
6394
6395
6396/**
6397 * xmlValidateElement:
6398 * @ctxt: the validation context
6399 * @doc: a document instance
6400 * @elem: an element instance
6401 *
6402 * Try to validate the subtree under an element
6403 *
6404 * returns 1 if valid or 0 otherwise
6405 */
6406
6407int
6408xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6409 xmlNodePtr child;
6410 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006411 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006412 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006413 int ret = 1;
6414
6415 if (elem == NULL) return(0);
6416
6417 /*
6418 * XInclude elements were added after parsing in the infoset,
6419 * they don't really mean anything validation wise.
6420 */
6421 if ((elem->type == XML_XINCLUDE_START) ||
6422 (elem->type == XML_XINCLUDE_END))
6423 return(1);
6424
6425 CHECK_DTD;
6426
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006427 /*
6428 * Entities references have to be handled separately
6429 */
6430 if (elem->type == XML_ENTITY_REF_NODE) {
6431 return(1);
6432 }
6433
Owen Taylor3473f882001-02-23 17:55:21 +00006434 ret &= xmlValidateOneElement(ctxt, doc, elem);
Daniel Veillard8874b942005-08-25 13:19:21 +00006435 if (elem->type == XML_ELEMENT_NODE) {
6436 attr = elem->properties;
6437 while (attr != NULL) {
6438 value = xmlNodeListGetString(doc, attr->children, 0);
6439 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6440 if (value != NULL)
6441 xmlFree((char *)value);
6442 attr= attr->next;
6443 }
6444 ns = elem->nsDef;
6445 while (ns != NULL) {
6446 if (elem->ns == NULL)
6447 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6448 ns, ns->href);
6449 else
6450 ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6451 elem->ns->prefix, ns, ns->href);
6452 ns = ns->next;
6453 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006454 }
Owen Taylor3473f882001-02-23 17:55:21 +00006455 child = elem->children;
6456 while (child != NULL) {
6457 ret &= xmlValidateElement(ctxt, doc, child);
6458 child = child->next;
6459 }
6460
6461 return(ret);
6462}
6463
Daniel Veillard8730c562001-02-26 10:49:57 +00006464/**
6465 * xmlValidateRef:
6466 * @ref: A reference to be validated
6467 * @ctxt: Validation context
6468 * @name: Name of ID we are searching for
6469 *
6470 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006471static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006472xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006473 const xmlChar *name) {
6474 xmlAttrPtr id;
6475 xmlAttrPtr attr;
6476
6477 if (ref == NULL)
6478 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006479 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006480 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006481 attr = ref->attr;
6482 if (attr == NULL) {
6483 xmlChar *dup, *str = NULL, *cur, save;
6484
6485 dup = xmlStrdup(name);
6486 if (dup == NULL) {
6487 ctxt->valid = 0;
6488 return;
6489 }
6490 cur = dup;
6491 while (*cur != 0) {
6492 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006493 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006494 save = *cur;
6495 *cur = 0;
6496 id = xmlGetID(ctxt->doc, str);
6497 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006498 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006499 "attribute %s line %d references an unknown ID \"%s\"\n",
6500 ref->name, ref->lineno, str);
6501 ctxt->valid = 0;
6502 }
6503 if (save == 0)
6504 break;
6505 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006506 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006507 }
6508 xmlFree(dup);
6509 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006510 id = xmlGetID(ctxt->doc, name);
6511 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006512 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006513 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006514 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006515 ctxt->valid = 0;
6516 }
6517 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6518 xmlChar *dup, *str = NULL, *cur, save;
6519
6520 dup = xmlStrdup(name);
6521 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006522 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006523 ctxt->valid = 0;
6524 return;
6525 }
6526 cur = dup;
6527 while (*cur != 0) {
6528 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006529 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006530 save = *cur;
6531 *cur = 0;
6532 id = xmlGetID(ctxt->doc, str);
6533 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006534 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006535 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006536 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006537 ctxt->valid = 0;
6538 }
6539 if (save == 0)
6540 break;
6541 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006542 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006543 }
6544 xmlFree(dup);
6545 }
6546}
6547
6548/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006549 * xmlWalkValidateList:
6550 * @data: Contents of current link
6551 * @user: Value supplied by the user
6552 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006553 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006554 */
6555static int
6556xmlWalkValidateList(const void *data, const void *user)
6557{
6558 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6559 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6560 return 1;
6561}
6562
6563/**
6564 * xmlValidateCheckRefCallback:
6565 * @ref_list: List of references
6566 * @ctxt: Validation context
6567 * @name: Name of ID we are searching for
6568 *
6569 */
6570static void
6571xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6572 const xmlChar *name) {
6573 xmlValidateMemo memo;
6574
6575 if (ref_list == NULL)
6576 return;
6577 memo.ctxt = ctxt;
6578 memo.name = name;
6579
6580 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6581
6582}
6583
6584/**
Owen Taylor3473f882001-02-23 17:55:21 +00006585 * xmlValidateDocumentFinal:
6586 * @ctxt: the validation context
6587 * @doc: a document instance
6588 *
6589 * Does the final step for the document validation once all the
6590 * incremental validation steps have been completed
6591 *
6592 * basically it does the following checks described by the XML Rec
6593 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006594 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006595 *
6596 * returns 1 if valid or 0 otherwise
6597 */
6598
6599int
6600xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6601 xmlRefTablePtr table;
6602
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006603 if (ctxt == NULL)
6604 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006605 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006606 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6607 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006608 return(0);
6609 }
6610
6611 /*
6612 * Check all the NOTATION/NOTATIONS attributes
6613 */
6614 /*
6615 * Check all the ENTITY/ENTITIES attributes definition for validity
6616 */
6617 /*
6618 * Check all the IDREF/IDREFS attributes definition for validity
6619 */
6620 table = (xmlRefTablePtr) doc->refs;
6621 ctxt->doc = doc;
6622 ctxt->valid = 1;
6623 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6624 return(ctxt->valid);
6625}
6626
6627/**
6628 * xmlValidateDtd:
6629 * @ctxt: the validation context
6630 * @doc: a document instance
6631 * @dtd: a dtd instance
6632 *
6633 * Try to validate the document against the dtd instance
6634 *
William M. Brack367df6e2004-10-23 18:14:36 +00006635 * Basically it does check all the definitions in the DtD.
6636 * Note the the internal subset (if present) is de-coupled
6637 * (i.e. not used), which could give problems if ID or IDREF
6638 * is present.
Owen Taylor3473f882001-02-23 17:55:21 +00006639 *
6640 * returns 1 if valid or 0 otherwise
6641 */
6642
6643int
6644xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6645 int ret;
William M. Brack367df6e2004-10-23 18:14:36 +00006646 xmlDtdPtr oldExt, oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006647 xmlNodePtr root;
6648
6649 if (dtd == NULL) return(0);
6650 if (doc == NULL) return(0);
6651 oldExt = doc->extSubset;
William M. Brack367df6e2004-10-23 18:14:36 +00006652 oldInt = doc->intSubset;
Owen Taylor3473f882001-02-23 17:55:21 +00006653 doc->extSubset = dtd;
William M. Brack367df6e2004-10-23 18:14:36 +00006654 doc->intSubset = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006655 ret = xmlValidateRoot(ctxt, doc);
6656 if (ret == 0) {
6657 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006658 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006659 return(ret);
6660 }
6661 if (doc->ids != NULL) {
6662 xmlFreeIDTable(doc->ids);
6663 doc->ids = NULL;
6664 }
6665 if (doc->refs != NULL) {
6666 xmlFreeRefTable(doc->refs);
6667 doc->refs = NULL;
6668 }
6669 root = xmlDocGetRootElement(doc);
6670 ret = xmlValidateElement(ctxt, doc, root);
6671 ret &= xmlValidateDocumentFinal(ctxt, doc);
6672 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006673 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006674 return(ret);
6675}
6676
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006677static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006678xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6679 const xmlChar *name ATTRIBUTE_UNUSED) {
6680 if (cur == NULL)
6681 return;
6682 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6683 xmlChar *notation = cur->content;
6684
Daniel Veillard878eab02002-02-19 13:46:09 +00006685 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006686 int ret;
6687
6688 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6689 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006690 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006691 }
6692 }
6693 }
6694}
6695
6696static void
Owen Taylor3473f882001-02-23 17:55:21 +00006697xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006698 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006699 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006700 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006701 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006702
Owen Taylor3473f882001-02-23 17:55:21 +00006703 if (cur == NULL)
6704 return;
6705 switch (cur->atype) {
6706 case XML_ATTRIBUTE_CDATA:
6707 case XML_ATTRIBUTE_ID:
6708 case XML_ATTRIBUTE_IDREF :
6709 case XML_ATTRIBUTE_IDREFS:
6710 case XML_ATTRIBUTE_NMTOKEN:
6711 case XML_ATTRIBUTE_NMTOKENS:
6712 case XML_ATTRIBUTE_ENUMERATION:
6713 break;
6714 case XML_ATTRIBUTE_ENTITY:
6715 case XML_ATTRIBUTE_ENTITIES:
6716 case XML_ATTRIBUTE_NOTATION:
6717 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006718
6719 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6720 cur->atype, cur->defaultValue);
6721 if ((ret == 0) && (ctxt->valid == 1))
6722 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006723 }
6724 if (cur->tree != NULL) {
6725 xmlEnumerationPtr tree = cur->tree;
6726 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006727 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006728 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006729 if ((ret == 0) && (ctxt->valid == 1))
6730 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006731 tree = tree->next;
6732 }
6733 }
6734 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006735 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6736 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006737 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006738 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006739 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006740 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006741 return;
6742 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006743
6744 if (doc != NULL)
6745 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6746 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006747 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006748 if ((elem == NULL) && (cur->parent != NULL) &&
6749 (cur->parent->type == XML_DTD_NODE))
6750 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006751 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006752 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006753 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006754 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006755 return;
6756 }
6757 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006758 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006759 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006760 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006761 ctxt->valid = 0;
6762 }
6763 }
Owen Taylor3473f882001-02-23 17:55:21 +00006764}
6765
6766/**
6767 * xmlValidateDtdFinal:
6768 * @ctxt: the validation context
6769 * @doc: a document instance
6770 *
6771 * Does the final step for the dtds validation once all the
6772 * subsets have been parsed
6773 *
6774 * basically it does the following checks described by the XML Rec
6775 * - check that ENTITY and ENTITIES type attributes default or
6776 * possible values matches one of the defined entities.
6777 * - check that NOTATION type attributes default or
6778 * possible values matches one of the defined notations.
6779 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006780 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006781 */
6782
6783int
6784xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006785 xmlDtdPtr dtd;
6786 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006787 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006788
Daniel Veillard2cba4152008-08-27 11:45:41 +00006789 if ((doc == NULL) || (ctxt == NULL)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006790 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6791 return(0);
6792 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006793 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006794 dtd = doc->intSubset;
6795 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6796 table = (xmlAttributeTablePtr) dtd->attributes;
6797 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006798 }
6799 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006800 entities = (xmlEntitiesTablePtr) dtd->entities;
6801 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6802 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006803 }
6804 dtd = doc->extSubset;
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 return(ctxt->valid);
6815}
6816
6817/**
6818 * xmlValidateDocument:
6819 * @ctxt: the validation context
6820 * @doc: a document instance
6821 *
6822 * Try to validate the document instance
6823 *
6824 * basically it does the all the checks described by the XML Rec
6825 * i.e. validates the internal and external subset (if present)
6826 * and validate the document tree.
6827 *
6828 * returns 1 if valid or 0 otherwise
6829 */
6830
6831int
6832xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6833 int ret;
6834 xmlNodePtr root;
6835
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006836 if (doc == NULL)
6837 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006838 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006839 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6840 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006841 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006842 }
Owen Taylor3473f882001-02-23 17:55:21 +00006843 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6844 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
William M. Brack8c22f9f2004-08-06 16:23:27 +00006845 xmlChar *sysID;
6846 if (doc->intSubset->SystemID != NULL) {
William M. Brackbebe7302004-08-05 06:46:47 +00006847 sysID = xmlBuildURI(doc->intSubset->SystemID,
6848 doc->URL);
William M. Brack8c22f9f2004-08-06 16:23:27 +00006849 if (sysID == NULL) {
6850 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6851 "Could not build URI for external subset \"%s\"\n",
6852 (const char *) doc->intSubset->SystemID);
6853 return 0;
6854 }
6855 } else
William M. Brackbebe7302004-08-05 06:46:47 +00006856 sysID = NULL;
William M. Brack8c22f9f2004-08-06 16:23:27 +00006857 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
William M. Brackbebe7302004-08-05 06:46:47 +00006858 (const xmlChar *)sysID);
William M. Brackbebe7302004-08-05 06:46:47 +00006859 if (sysID != NULL)
6860 xmlFree(sysID);
Owen Taylor3473f882001-02-23 17:55:21 +00006861 if (doc->extSubset == NULL) {
6862 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006863 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006864 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006865 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006866 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006867 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006868 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006869 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006870 }
6871 return(0);
6872 }
6873 }
6874
6875 if (doc->ids != NULL) {
6876 xmlFreeIDTable(doc->ids);
6877 doc->ids = NULL;
6878 }
6879 if (doc->refs != NULL) {
6880 xmlFreeRefTable(doc->refs);
6881 doc->refs = NULL;
6882 }
6883 ret = xmlValidateDtdFinal(ctxt, doc);
6884 if (!xmlValidateRoot(ctxt, doc)) return(0);
6885
6886 root = xmlDocGetRootElement(doc);
6887 ret &= xmlValidateElement(ctxt, doc, root);
6888 ret &= xmlValidateDocumentFinal(ctxt, doc);
6889 return(ret);
6890}
6891
Owen Taylor3473f882001-02-23 17:55:21 +00006892/************************************************************************
6893 * *
6894 * Routines for dynamic validation editing *
6895 * *
6896 ************************************************************************/
6897
6898/**
6899 * xmlValidGetPotentialChildren:
6900 * @ctree: an element content tree
Daniel Veillard7802ba52005-10-27 11:56:20 +00006901 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006902 * @len: a pointer to the number of element in the list
6903 * @max: the size of the array
6904 *
6905 * Build/extend a list of potential children allowed by the content tree
6906 *
6907 * returns the number of element in the list, or -1 in case of error.
6908 */
6909
6910int
Daniel Veillard7802ba52005-10-27 11:56:20 +00006911xmlValidGetPotentialChildren(xmlElementContent *ctree,
6912 const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006913 int *len, int max) {
6914 int i;
6915
Daniel Veillard7802ba52005-10-27 11:56:20 +00006916 if ((ctree == NULL) || (names == NULL) || (len == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006917 return(-1);
6918 if (*len >= max) return(*len);
6919
6920 switch (ctree->type) {
6921 case XML_ELEMENT_CONTENT_PCDATA:
6922 for (i = 0; i < *len;i++)
Daniel Veillard7802ba52005-10-27 11:56:20 +00006923 if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
6924 names[(*len)++] = BAD_CAST "#PCDATA";
Owen Taylor3473f882001-02-23 17:55:21 +00006925 break;
6926 case XML_ELEMENT_CONTENT_ELEMENT:
6927 for (i = 0; i < *len;i++)
Daniel Veillard7802ba52005-10-27 11:56:20 +00006928 if (xmlStrEqual(ctree->name, names[i])) return(*len);
6929 names[(*len)++] = ctree->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006930 break;
6931 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard7802ba52005-10-27 11:56:20 +00006932 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6933 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
Owen Taylor3473f882001-02-23 17:55:21 +00006934 break;
6935 case XML_ELEMENT_CONTENT_OR:
Daniel Veillard7802ba52005-10-27 11:56:20 +00006936 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6937 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
Owen Taylor3473f882001-02-23 17:55:21 +00006938 break;
6939 }
6940
6941 return(*len);
6942}
6943
William M. Brack9333cc22004-06-24 08:33:40 +00006944/*
6945 * Dummy function to suppress messages while we try out valid elements
6946 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00006947static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
William M. Brack9333cc22004-06-24 08:33:40 +00006948 const char *msg ATTRIBUTE_UNUSED, ...) {
6949 return;
6950}
6951
Owen Taylor3473f882001-02-23 17:55:21 +00006952/**
6953 * xmlValidGetValidElements:
6954 * @prev: an element to insert after
6955 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006956 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006957 * @max: the size of the array
6958 *
6959 * This function returns the list of authorized children to insert
6960 * within an existing tree while respecting the validity constraints
6961 * forced by the Dtd. The insertion point is defined using @prev and
6962 * @next in the following ways:
6963 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6964 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6965 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6966 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6967 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6968 *
6969 * pointers to the element names are inserted at the beginning of the array
6970 * and do not need to be freed.
6971 *
6972 * returns the number of element in the list, or -1 in case of error. If
6973 * the function returns the value @max the caller is invited to grow the
6974 * receiving array and retry.
6975 */
6976
6977int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006978xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006979 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006980 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006981 int nb_valid_elements = 0;
6982 const xmlChar *elements[256];
6983 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006984 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006985
6986 xmlNode *ref_node;
6987 xmlNode *parent;
6988 xmlNode *test_node;
6989
6990 xmlNode *prev_next;
6991 xmlNode *next_prev;
6992 xmlNode *parent_childs;
6993 xmlNode *parent_last;
6994
6995 xmlElement *element_desc;
6996
6997 if (prev == NULL && next == NULL)
6998 return(-1);
6999
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00007000 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00007001 if (max <= 0) return(-1);
7002
William M. Brack9333cc22004-06-24 08:33:40 +00007003 memset(&vctxt, 0, sizeof (xmlValidCtxt));
7004 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
7005
Owen Taylor3473f882001-02-23 17:55:21 +00007006 nb_valid_elements = 0;
7007 ref_node = prev ? prev : next;
7008 parent = ref_node->parent;
7009
7010 /*
7011 * Retrieves the parent element declaration
7012 */
7013 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
7014 parent->name);
7015 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
7016 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
7017 parent->name);
7018 if (element_desc == NULL) return(-1);
7019
7020 /*
7021 * Do a backup of the current tree structure
7022 */
7023 prev_next = prev ? prev->next : NULL;
7024 next_prev = next ? next->prev : NULL;
7025 parent_childs = parent->children;
7026 parent_last = parent->last;
7027
7028 /*
7029 * Creates a dummy node and insert it into the tree
7030 */
Daniel Veillard95ddcd32004-10-26 21:53:55 +00007031 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007032 test_node->parent = parent;
7033 test_node->prev = prev;
7034 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00007035 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00007036
7037 if (prev) prev->next = test_node;
7038 else parent->children = test_node;
7039
7040 if (next) next->prev = test_node;
7041 else parent->last = test_node;
7042
7043 /*
7044 * Insert each potential child node and check if the parent is
7045 * still valid
7046 */
7047 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
7048 elements, &nb_elements, 256);
7049
7050 for (i = 0;i < nb_elements;i++) {
7051 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00007052 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007053 int j;
7054
7055 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00007056 if (xmlStrEqual(elements[i], names[j])) break;
7057 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00007058 if (nb_valid_elements >= max) break;
7059 }
7060 }
7061
7062 /*
7063 * Restore the tree structure
7064 */
7065 if (prev) prev->next = prev_next;
7066 if (next) next->prev = next_prev;
7067 parent->children = parent_childs;
7068 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00007069
7070 /*
7071 * Free up the dummy node
7072 */
7073 test_node->name = name;
7074 xmlFreeNode(test_node);
7075
Owen Taylor3473f882001-02-23 17:55:21 +00007076 return(nb_valid_elements);
7077}
Daniel Veillard4432df22003-09-28 18:58:27 +00007078#endif /* LIBXML_VALID_ENABLED */
7079
Daniel Veillard5d4644e2005-04-01 13:11:58 +00007080#define bottom_valid
7081#include "elfgcchack.h"