blob: 8a29831d0df6605d6af399954d0735a2a840bf47 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * valid.c : part of the code use to do the DTD handling and the validity
3 * checking
4 *
5 * See Copyright for the status of this software.
6 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00007 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00008 */
9
Daniel Veillard34ce8be2002-03-18 19:37:11 +000010#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000011#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000012
Owen Taylor3473f882001-02-23 17:55:21 +000013#include <string.h>
14
15#ifdef HAVE_STDLIB_H
16#include <stdlib.h>
17#endif
18
19#include <libxml/xmlmemory.h>
20#include <libxml/hash.h>
Daniel Veillard29b17482004-08-16 00:39:03 +000021#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <libxml/valid.h>
23#include <libxml/parser.h>
24#include <libxml/parserInternals.h>
25#include <libxml/xmlerror.h>
26#include <libxml/list.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000027#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000028
Daniel Veillard4432df22003-09-28 18:58:27 +000029static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
30 int create);
Daniel Veillarde62d36c2001-05-15 08:53:16 +000031/* #define DEBUG_VALID_ALGO */
Daniel Veillard5acfd6b2002-09-18 16:29:02 +000032/* #define DEBUG_REGEXP_ALGO */
Daniel Veillarde62d36c2001-05-15 08:53:16 +000033
Daniel Veillarda646cfd2002-09-17 21:50:03 +000034#define TODO \
35 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
37 __FILE__, __LINE__);
Owen Taylor3473f882001-02-23 17:55:21 +000038
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000039/************************************************************************
40 * *
41 * Error handling routines *
42 * *
43 ************************************************************************/
44
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000045/**
Daniel Veillardce9457f2003-10-05 21:33:18 +000046 * xmlVErrMemory:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000047 * @ctxt: an XML validation parser context
48 * @extra: extra informations
49 *
50 * Handle an out of memory error
51 */
52static void
Daniel Veillardce9457f2003-10-05 21:33:18 +000053xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000054{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000055 xmlGenericErrorFunc channel = NULL;
56 xmlParserCtxtPtr pctxt = NULL;
57 void *data = NULL;
58
59 if (ctxt != NULL) {
60 channel = ctxt->error;
61 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +000062 /* Use the special values to detect if it is part of a parsing
63 context */
64 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
65 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
66 pctxt = ctxt->userData;
67 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +000068 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000069 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000070 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000071 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000072 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
73 "Memory allocation failed : %s\n", extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000074 else
Daniel Veillard73000572003-10-11 11:26:42 +000075 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000076 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000077 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
78 "Memory allocation failed\n");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000079}
80
81/**
82 * xmlErrValid:
83 * @ctxt: an XML validation parser context
Daniel Veillardbb5abab2003-10-03 22:21:51 +000084 * @error: the error number
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000085 * @extra: extra informations
86 *
87 * Handle a validation error
88 */
89static void
Daniel Veillardf88d8cf2003-12-08 10:25:02 +000090xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000091 const char *msg, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000092{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000093 xmlGenericErrorFunc channel = NULL;
94 xmlParserCtxtPtr pctxt = NULL;
95 void *data = NULL;
96
97 if (ctxt != NULL) {
98 channel = ctxt->error;
99 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000100 /* Use the special values to detect if it is part of a parsing
101 context */
102 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
103 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
104 pctxt = ctxt->userData;
105 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000106 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000107 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +0000108 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000109 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000110 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
111 msg, extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000112 else
Daniel Veillard73000572003-10-11 11:26:42 +0000113 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000114 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000115 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
116 msg);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000117}
118
Daniel Veillardf54cd532004-02-25 11:52:31 +0000119#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
120/**
121 * xmlErrValidNode:
122 * @ctxt: an XML validation parser context
123 * @node: the node raising the error
124 * @error: the error number
125 * @str1: extra informations
126 * @str2: extra informations
127 * @str3: extra informations
128 *
129 * Handle a validation error, provide contextual informations
130 */
131static void
132xmlErrValidNode(xmlValidCtxtPtr ctxt,
133 xmlNodePtr node, xmlParserErrors error,
134 const char *msg, const xmlChar * str1,
135 const xmlChar * str2, const xmlChar * str3)
136{
137 xmlStructuredErrorFunc schannel = NULL;
138 xmlGenericErrorFunc channel = NULL;
139 xmlParserCtxtPtr pctxt = NULL;
140 void *data = NULL;
141
142 if (ctxt != NULL) {
143 channel = ctxt->error;
144 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000145 /* Use the special values to detect if it is part of a parsing
146 context */
147 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
148 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
149 pctxt = ctxt->userData;
150 }
Daniel Veillardf54cd532004-02-25 11:52:31 +0000151 }
152 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
153 XML_ERR_ERROR, NULL, 0,
154 (const char *) str1,
155 (const char *) str1,
156 (const char *) str3, 0, 0, msg, str1, str2, str3);
157}
158#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
159
Daniel Veillardd61e8fb2003-10-19 21:59:17 +0000160#ifdef LIBXML_VALID_ENABLED
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000161/**
162 * xmlErrValidNodeNr:
163 * @ctxt: an XML validation parser context
164 * @node: the node raising the error
165 * @error: the error number
166 * @str1: extra informations
167 * @int2: extra informations
168 * @str3: extra informations
169 *
170 * Handle a validation error, provide contextual informations
171 */
172static void
Daniel Veillard72b9e292003-10-28 15:44:17 +0000173xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000174 xmlNodePtr node, xmlParserErrors error,
175 const char *msg, const xmlChar * str1,
176 int int2, const xmlChar * str3)
177{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000178 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000179 xmlGenericErrorFunc channel = NULL;
180 xmlParserCtxtPtr pctxt = NULL;
181 void *data = NULL;
182
183 if (ctxt != NULL) {
184 channel = ctxt->error;
185 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000186 /* Use the special values to detect if it is part of a parsing
187 context */
188 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
189 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
190 pctxt = ctxt->userData;
191 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000192 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000193 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000194 XML_ERR_ERROR, NULL, 0,
195 (const char *) str1,
196 (const char *) str3,
197 NULL, int2, 0, msg, str1, int2, str3);
198}
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000199
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000200/**
201 * xmlErrValidWarning:
202 * @ctxt: an XML validation parser context
203 * @node: the node raising the error
204 * @error: the error number
William M. Brackedb65a72004-02-06 07:36:04 +0000205 * @str1: extra information
206 * @str2: extra information
207 * @str3: extra information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000208 *
William M. Brackedb65a72004-02-06 07:36:04 +0000209 * Handle a validation error, provide contextual information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000210 */
211static void
William M. Brackedb65a72004-02-06 07:36:04 +0000212xmlErrValidWarning(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000213 xmlNodePtr node, xmlParserErrors error,
214 const char *msg, const xmlChar * str1,
215 const xmlChar * str2, const xmlChar * str3)
216{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000217 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000218 xmlGenericErrorFunc channel = NULL;
219 xmlParserCtxtPtr pctxt = NULL;
220 void *data = NULL;
221
222 if (ctxt != NULL) {
William M. Bracke4d526f2004-12-18 00:01:21 +0000223 channel = ctxt->warning;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000224 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000225 /* Use the special values to detect if it is part of a parsing
226 context */
227 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
228 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
229 pctxt = ctxt->userData;
230 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000231 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000232 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000233 XML_ERR_WARNING, NULL, 0,
234 (const char *) str1,
235 (const char *) str1,
236 (const char *) str3, 0, 0, msg, str1, str2, str3);
237}
238
239
Daniel Veillardea7751d2002-12-20 00:16:24 +0000240
241#ifdef LIBXML_REGEXP_ENABLED
242/*
243 * If regexp are enabled we can do continuous validation without the
244 * need of a tree to validate the content model. this is done in each
245 * callbacks.
246 * Each xmlValidState represent the validation state associated to the
247 * set of nodes currently open from the document root to the current element.
248 */
249
250
251typedef struct _xmlValidState {
252 xmlElementPtr elemDecl; /* pointer to the content model */
253 xmlNodePtr node; /* pointer to the current node */
254 xmlRegExecCtxtPtr exec; /* regexp runtime */
255} _xmlValidState;
256
257
258static int
259vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000260 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000261 ctxt->vstateMax = 10;
262 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
263 sizeof(ctxt->vstateTab[0]));
264 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000265 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000266 return(-1);
267 }
268 }
269
270 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000271 xmlValidState *tmp;
272
273 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
274 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
275 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000276 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000277 return(-1);
278 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000279 ctxt->vstateMax *= 2;
280 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000281 }
282 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
283 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
284 ctxt->vstateTab[ctxt->vstateNr].node = node;
285 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
286 if (elemDecl->contModel == NULL)
287 xmlValidBuildContentModel(ctxt, elemDecl);
288 if (elemDecl->contModel != NULL) {
289 ctxt->vstateTab[ctxt->vstateNr].exec =
290 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
291 } else {
292 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000293 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
294 XML_ERR_INTERNAL_ERROR,
295 "Failed to build content model regexp for %s\n",
296 node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000297 }
298 }
299 return(ctxt->vstateNr++);
300}
301
302static int
303vstateVPop(xmlValidCtxtPtr ctxt) {
304 xmlElementPtr elemDecl;
305
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000306 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000307 ctxt->vstateNr--;
308 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
309 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
310 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
311 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
312 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
313 }
314 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
315 if (ctxt->vstateNr >= 1)
316 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
317 else
318 ctxt->vstate = NULL;
319 return(ctxt->vstateNr);
320}
321
322#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000323/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000324 * If regexp are not enabled, it uses a home made algorithm less
325 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000326 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000327 * only restriction is on the deepness of the tree limited by the
328 * size of the occurs bitfield
329 *
330 * this is the content of a saved state for rollbacks
331 */
332
333#define ROLLBACK_OR 0
334#define ROLLBACK_PARENT 1
335
Daniel Veillardb44025c2001-10-11 22:55:55 +0000336typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000337 xmlElementContentPtr cont; /* pointer to the content model subtree */
338 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000339 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000340 unsigned char depth; /* current depth in the overall tree */
341 unsigned char state; /* ROLLBACK_XXX */
342} _xmlValidState;
343
Daniel Veillardfc57b412002-04-29 15:50:14 +0000344#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000345#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
346#define CONT ctxt->vstate->cont
347#define NODE ctxt->vstate->node
348#define DEPTH ctxt->vstate->depth
349#define OCCURS ctxt->vstate->occurs
350#define STATE ctxt->vstate->state
351
Daniel Veillard5344c602001-12-31 16:37:34 +0000352#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
353#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000354
Daniel Veillard5344c602001-12-31 16:37:34 +0000355#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
356#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000357
358static int
359vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
360 xmlNodePtr node, unsigned char depth, long occurs,
361 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000362 int i = ctxt->vstateNr - 1;
363
Daniel Veillard940492d2002-04-15 10:15:25 +0000364 if (ctxt->vstateNr > MAX_RECURSE) {
365 return(-1);
366 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000367 if (ctxt->vstateTab == NULL) {
368 ctxt->vstateMax = 8;
369 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
370 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
371 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000372 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000373 return(-1);
374 }
375 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000376 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000377 xmlValidState *tmp;
378
379 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
380 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
381 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000382 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000383 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000384 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000385 ctxt->vstateMax *= 2;
386 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000387 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000388 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000389 /*
390 * Don't push on the stack a state already here
391 */
392 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
393 (ctxt->vstateTab[i].node == node) &&
394 (ctxt->vstateTab[i].depth == depth) &&
395 (ctxt->vstateTab[i].occurs == occurs) &&
396 (ctxt->vstateTab[i].state == state))
397 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000398 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
399 ctxt->vstateTab[ctxt->vstateNr].node = node;
400 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
401 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
402 ctxt->vstateTab[ctxt->vstateNr].state = state;
403 return(ctxt->vstateNr++);
404}
405
406static int
407vstateVPop(xmlValidCtxtPtr ctxt) {
408 if (ctxt->vstateNr <= 1) return(-1);
409 ctxt->vstateNr--;
410 ctxt->vstate = &ctxt->vstateTab[0];
411 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
412 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
413 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
414 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
415 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
416 return(ctxt->vstateNr);
417}
418
Daniel Veillard118aed72002-09-24 14:13:13 +0000419#endif /* LIBXML_REGEXP_ENABLED */
420
Daniel Veillard1c732d22002-11-30 11:22:59 +0000421static int
422nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
423{
424 if (ctxt->nodeMax <= 0) {
425 ctxt->nodeMax = 4;
426 ctxt->nodeTab =
427 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
428 sizeof(ctxt->nodeTab[0]));
429 if (ctxt->nodeTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000430 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000431 ctxt->nodeMax = 0;
432 return (0);
433 }
434 }
435 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000436 xmlNodePtr *tmp;
437 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
438 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
439 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000440 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000441 return (0);
442 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000443 ctxt->nodeMax *= 2;
444 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000445 }
446 ctxt->nodeTab[ctxt->nodeNr] = value;
447 ctxt->node = value;
448 return (ctxt->nodeNr++);
449}
450static xmlNodePtr
451nodeVPop(xmlValidCtxtPtr ctxt)
452{
453 xmlNodePtr ret;
454
455 if (ctxt->nodeNr <= 0)
456 return (0);
457 ctxt->nodeNr--;
458 if (ctxt->nodeNr > 0)
459 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
460 else
461 ctxt->node = NULL;
462 ret = ctxt->nodeTab[ctxt->nodeNr];
463 ctxt->nodeTab[ctxt->nodeNr] = 0;
464 return (ret);
465}
Owen Taylor3473f882001-02-23 17:55:21 +0000466
Owen Taylor3473f882001-02-23 17:55:21 +0000467#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000468static void
469xmlValidPrintNode(xmlNodePtr cur) {
470 if (cur == NULL) {
471 xmlGenericError(xmlGenericErrorContext, "null");
472 return;
473 }
474 switch (cur->type) {
475 case XML_ELEMENT_NODE:
476 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
477 break;
478 case XML_TEXT_NODE:
479 xmlGenericError(xmlGenericErrorContext, "text ");
480 break;
481 case XML_CDATA_SECTION_NODE:
482 xmlGenericError(xmlGenericErrorContext, "cdata ");
483 break;
484 case XML_ENTITY_REF_NODE:
485 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
486 break;
487 case XML_PI_NODE:
488 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
489 break;
490 case XML_COMMENT_NODE:
491 xmlGenericError(xmlGenericErrorContext, "comment ");
492 break;
493 case XML_ATTRIBUTE_NODE:
494 xmlGenericError(xmlGenericErrorContext, "?attr? ");
495 break;
496 case XML_ENTITY_NODE:
497 xmlGenericError(xmlGenericErrorContext, "?ent? ");
498 break;
499 case XML_DOCUMENT_NODE:
500 xmlGenericError(xmlGenericErrorContext, "?doc? ");
501 break;
502 case XML_DOCUMENT_TYPE_NODE:
503 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
504 break;
505 case XML_DOCUMENT_FRAG_NODE:
506 xmlGenericError(xmlGenericErrorContext, "?frag? ");
507 break;
508 case XML_NOTATION_NODE:
509 xmlGenericError(xmlGenericErrorContext, "?nota? ");
510 break;
511 case XML_HTML_DOCUMENT_NODE:
512 xmlGenericError(xmlGenericErrorContext, "?html? ");
513 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000514#ifdef LIBXML_DOCB_ENABLED
515 case XML_DOCB_DOCUMENT_NODE:
516 xmlGenericError(xmlGenericErrorContext, "?docb? ");
517 break;
518#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000519 case XML_DTD_NODE:
520 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
521 break;
522 case XML_ELEMENT_DECL:
523 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
524 break;
525 case XML_ATTRIBUTE_DECL:
526 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
527 break;
528 case XML_ENTITY_DECL:
529 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
530 break;
531 case XML_NAMESPACE_DECL:
532 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
533 break;
534 case XML_XINCLUDE_START:
535 xmlGenericError(xmlGenericErrorContext, "incstart ");
536 break;
537 case XML_XINCLUDE_END:
538 xmlGenericError(xmlGenericErrorContext, "incend ");
539 break;
540 }
541}
542
543static void
544xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000545 if (cur == NULL)
546 xmlGenericError(xmlGenericErrorContext, "null ");
547 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000548 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000549 cur = cur->next;
550 }
551}
552
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000553static void
554xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000555 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000556
557 expr[0] = 0;
558 xmlGenericError(xmlGenericErrorContext, "valid: ");
559 xmlValidPrintNodeList(cur);
560 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000561 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000562 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
563}
564
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000565static void
566xmlValidDebugState(xmlValidStatePtr state) {
567 xmlGenericError(xmlGenericErrorContext, "(");
568 if (state->cont == NULL)
569 xmlGenericError(xmlGenericErrorContext, "null,");
570 else
571 switch (state->cont->type) {
572 case XML_ELEMENT_CONTENT_PCDATA:
573 xmlGenericError(xmlGenericErrorContext, "pcdata,");
574 break;
575 case XML_ELEMENT_CONTENT_ELEMENT:
576 xmlGenericError(xmlGenericErrorContext, "%s,",
577 state->cont->name);
578 break;
579 case XML_ELEMENT_CONTENT_SEQ:
580 xmlGenericError(xmlGenericErrorContext, "seq,");
581 break;
582 case XML_ELEMENT_CONTENT_OR:
583 xmlGenericError(xmlGenericErrorContext, "or,");
584 break;
585 }
586 xmlValidPrintNode(state->node);
587 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
588 state->depth, state->occurs, state->state);
589}
590
591static void
592xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
593 int i, j;
594
595 xmlGenericError(xmlGenericErrorContext, "state: ");
596 xmlValidDebugState(ctxt->vstate);
597 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
598 ctxt->vstateNr - 1);
599 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
600 xmlValidDebugState(&ctxt->vstateTab[j]);
601 xmlGenericError(xmlGenericErrorContext, "\n");
602}
603
604/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000605#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000606 *****/
607
608#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000609#define DEBUG_VALID_MSG(m) \
610 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
611
Owen Taylor3473f882001-02-23 17:55:21 +0000612#else
613#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000614#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000615#endif
616
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000617/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000618
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000619
Owen Taylor3473f882001-02-23 17:55:21 +0000620#define CHECK_DTD \
621 if (doc == NULL) return(0); \
622 else if ((doc->intSubset == NULL) && \
623 (doc->extSubset == NULL)) return(0)
624
Owen Taylor3473f882001-02-23 17:55:21 +0000625xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
626
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000627#ifdef LIBXML_REGEXP_ENABLED
628
629/************************************************************************
630 * *
631 * Content model validation based on the regexps *
632 * *
633 ************************************************************************/
634
635/**
636 * xmlValidBuildAContentModel:
637 * @content: the content model
638 * @ctxt: the schema parser context
639 * @name: the element name whose content is being built
640 *
641 * Generate the automata sequence needed for that type
642 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000643 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000644 */
645static int
646xmlValidBuildAContentModel(xmlElementContentPtr content,
647 xmlValidCtxtPtr ctxt,
648 const xmlChar *name) {
649 if (content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000650 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
651 "Found NULL content in content model of %s\n",
652 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000653 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000654 }
655 switch (content->type) {
656 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000657 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
658 "Found PCDATA in content model of %s\n",
659 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000660 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000661 break;
662 case XML_ELEMENT_CONTENT_ELEMENT: {
663 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000664 xmlChar fn[50];
665 xmlChar *fullname;
666
667 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
668 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000669 xmlVErrMemory(ctxt, "Building content model");
Daniel Veillardc00cda82003-04-07 10:22:39 +0000670 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000671 }
672
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000673 switch (content->ocur) {
674 case XML_ELEMENT_CONTENT_ONCE:
675 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000676 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000677 break;
678 case XML_ELEMENT_CONTENT_OPT:
679 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000680 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000681 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
682 break;
683 case XML_ELEMENT_CONTENT_PLUS:
684 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000685 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000686 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000687 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000688 break;
689 case XML_ELEMENT_CONTENT_MULT:
William M. Brack8b0cbb02004-04-17 13:31:06 +0000690 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
691 ctxt->state, NULL);
692 xmlAutomataNewTransition(ctxt->am,
693 ctxt->state, ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000694 break;
695 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000696 if ((fullname != fn) && (fullname != content->name))
697 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000698 break;
699 }
700 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000701 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000702 xmlElementContentOccur ocur;
703
704 /*
705 * Simply iterate over the content
706 */
707 oldstate = ctxt->state;
708 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000709 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
710 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
711 oldstate = ctxt->state;
712 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000713 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000714 xmlValidBuildAContentModel(content->c1, ctxt, name);
715 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000716 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
717 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
718 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000719 oldend = ctxt->state;
720 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000721 switch (ocur) {
722 case XML_ELEMENT_CONTENT_ONCE:
723 break;
724 case XML_ELEMENT_CONTENT_OPT:
725 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
726 break;
727 case XML_ELEMENT_CONTENT_MULT:
728 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000729 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000730 break;
731 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000732 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000733 break;
734 }
735 break;
736 }
737 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000738 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000739 xmlElementContentOccur ocur;
740
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000741 ocur = content->ocur;
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000742 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
743 (ocur == XML_ELEMENT_CONTENT_MULT)) {
744 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
745 ctxt->state, NULL);
746 }
747 oldstate = ctxt->state;
748 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000749
750 /*
751 * iterate over the subtypes and remerge the end with an
752 * epsilon transition
753 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000754 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000755 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000756 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000757 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000758 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000759 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
760 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000761 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000762 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000763 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
764 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000765 switch (ocur) {
766 case XML_ELEMENT_CONTENT_ONCE:
767 break;
768 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000769 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000770 break;
771 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000772 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
773 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000774 break;
775 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000776 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000777 break;
778 }
779 break;
780 }
781 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000782 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
783 "ContentModel broken for element %s\n",
784 (const char *) name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000785 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000786 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000787 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000788}
789/**
790 * xmlValidBuildContentModel:
791 * @ctxt: a validation context
792 * @elem: an element declaration node
793 *
794 * (Re)Build the automata associated to the content model of this
795 * element
796 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000797 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000798 */
799int
800xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000801
802 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000803 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000804 if (elem->type != XML_ELEMENT_DECL)
805 return(0);
806 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
807 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000808 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000809 if (elem->contModel != NULL) {
810 if (!xmlRegexpIsDeterminist(elem->contModel)) {
811 ctxt->valid = 0;
812 return(0);
813 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000814 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000815 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000816
817 ctxt->am = xmlNewAutomata();
818 if (ctxt->am == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000819 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
820 XML_ERR_INTERNAL_ERROR,
821 "Cannot create automata for element %s\n",
822 elem->name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000823 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000824 }
William M. Brack78637da2003-07-31 14:47:38 +0000825 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000826 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
827 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000828 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000829 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000830 char expr[5000];
831 expr[0] = 0;
832 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000833 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
834 XML_DTD_CONTENT_NOT_DETERMINIST,
835 "Content model of %s is not determinist: %s\n",
836 elem->name, BAD_CAST expr, NULL);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000837#ifdef DEBUG_REGEXP_ALGO
838 xmlRegexpPrint(stderr, elem->contModel);
839#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000840 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000841 ctxt->state = NULL;
842 xmlFreeAutomata(ctxt->am);
843 ctxt->am = NULL;
844 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000845 }
846 ctxt->state = NULL;
847 xmlFreeAutomata(ctxt->am);
848 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000849 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000850}
851
852#endif /* LIBXML_REGEXP_ENABLED */
853
Owen Taylor3473f882001-02-23 17:55:21 +0000854/****************************************************************
855 * *
856 * Util functions for data allocation/deallocation *
857 * *
858 ****************************************************************/
859
860/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000861 * xmlNewValidCtxt:
862 *
863 * Allocate a validation context structure.
864 *
865 * Returns NULL if not, otherwise the new validation context structure
866 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000867xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000868 xmlValidCtxtPtr ret;
869
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000870 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000871 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000872 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000873 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000874
875 (void) memset(ret, 0, sizeof (xmlValidCtxt));
876
877 return (ret);
878}
879
880/**
881 * xmlFreeValidCtxt:
882 * @cur: the validation context to free
883 *
884 * Free a validation context structure.
885 */
886void
887xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
Daniel Veillardc0be74b2004-11-03 19:16:55 +0000888 if (cur->vstateTab != NULL)
889 xmlFree(cur->vstateTab);
890 if (cur->nodeTab != NULL)
891 xmlFree(cur->nodeTab);
Daniel Veillarda37aab82003-06-09 09:10:36 +0000892 xmlFree(cur);
893}
894
Daniel Veillard4432df22003-09-28 18:58:27 +0000895#endif /* LIBXML_VALID_ENABLED */
896
Daniel Veillarda37aab82003-06-09 09:10:36 +0000897/**
Owen Taylor3473f882001-02-23 17:55:21 +0000898 * xmlNewElementContent:
899 * @name: the subelement name or NULL
900 * @type: the type of element content decl
901 *
902 * Allocate an element content structure.
903 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000904 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000905 */
906xmlElementContentPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000907xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000908 xmlElementContentPtr ret;
909
910 switch(type) {
911 case XML_ELEMENT_CONTENT_ELEMENT:
912 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000913 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
914 "xmlNewElementContent : name == NULL !\n",
915 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000916 }
917 break;
918 case XML_ELEMENT_CONTENT_PCDATA:
919 case XML_ELEMENT_CONTENT_SEQ:
920 case XML_ELEMENT_CONTENT_OR:
921 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000922 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
923 "xmlNewElementContent : name != NULL !\n",
924 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000925 }
926 break;
927 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000928 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
929 "Internal: ELEMENT content corrupted invalid type\n",
930 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000931 return(NULL);
932 }
933 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
934 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000935 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000936 return(NULL);
937 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000938 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000939 ret->type = type;
940 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000941 if (name != NULL) {
942 xmlChar *prefix = NULL;
943 ret->name = xmlSplitQName2(name, &prefix);
944 if (ret->name == NULL)
945 ret->name = xmlStrdup(name);
946 ret->prefix = prefix;
947 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000948 ret->name = NULL;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000949 ret->prefix = NULL;
950 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000951 ret->c1 = ret->c2 = ret->parent = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000952 return(ret);
953}
954
955/**
956 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000957 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +0000958 *
959 * Build a copy of an element content description.
960 *
961 * Returns the new xmlElementContentPtr or NULL in case of error.
962 */
963xmlElementContentPtr
964xmlCopyElementContent(xmlElementContentPtr cur) {
965 xmlElementContentPtr ret;
966
967 if (cur == NULL) return(NULL);
968 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
969 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000970 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000971 return(NULL);
972 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000973 if (cur->prefix != NULL)
974 ret->prefix = xmlStrdup(cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000975 ret->ocur = cur->ocur;
976 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000977 if (ret->c1 != NULL)
978 ret->c1->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000979 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000980 if (ret->c2 != NULL)
981 ret->c2->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000982 return(ret);
983}
984
985/**
986 * xmlFreeElementContent:
987 * @cur: the element content tree to free
988 *
989 * Free an element content structure. This is a recursive call !
990 */
991void
992xmlFreeElementContent(xmlElementContentPtr cur) {
993 if (cur == NULL) return;
994 switch (cur->type) {
995 case XML_ELEMENT_CONTENT_PCDATA:
996 case XML_ELEMENT_CONTENT_ELEMENT:
997 case XML_ELEMENT_CONTENT_SEQ:
998 case XML_ELEMENT_CONTENT_OR:
999 break;
1000 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001001 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1002 "Internal: ELEMENT content corrupted invalid type\n",
1003 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001004 return;
1005 }
1006 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
1007 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
1008 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001009 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001010 xmlFree(cur);
1011}
1012
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001013#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001014/**
1015 * xmlDumpElementContent:
1016 * @buf: An XML buffer
1017 * @content: An element table
1018 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1019 *
1020 * This will dump the content of the element table as an XML DTD definition
1021 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001022static void
Owen Taylor3473f882001-02-23 17:55:21 +00001023xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1024 if (content == NULL) return;
1025
1026 if (glob) xmlBufferWriteChar(buf, "(");
1027 switch (content->type) {
1028 case XML_ELEMENT_CONTENT_PCDATA:
1029 xmlBufferWriteChar(buf, "#PCDATA");
1030 break;
1031 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001032 if (content->prefix != NULL) {
1033 xmlBufferWriteCHAR(buf, content->prefix);
1034 xmlBufferWriteChar(buf, ":");
1035 }
Owen Taylor3473f882001-02-23 17:55:21 +00001036 xmlBufferWriteCHAR(buf, content->name);
1037 break;
1038 case XML_ELEMENT_CONTENT_SEQ:
1039 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1040 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1041 xmlDumpElementContent(buf, content->c1, 1);
1042 else
1043 xmlDumpElementContent(buf, content->c1, 0);
1044 xmlBufferWriteChar(buf, " , ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001045 if ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1046 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
1047 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001048 xmlDumpElementContent(buf, content->c2, 1);
1049 else
1050 xmlDumpElementContent(buf, content->c2, 0);
1051 break;
1052 case XML_ELEMENT_CONTENT_OR:
1053 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1054 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1055 xmlDumpElementContent(buf, content->c1, 1);
1056 else
1057 xmlDumpElementContent(buf, content->c1, 0);
1058 xmlBufferWriteChar(buf, " | ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001059 if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1060 ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
1061 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001062 xmlDumpElementContent(buf, content->c2, 1);
1063 else
1064 xmlDumpElementContent(buf, content->c2, 0);
1065 break;
1066 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001067 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1068 "Internal: ELEMENT content corrupted invalid type\n",
1069 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001070 }
1071 if (glob)
1072 xmlBufferWriteChar(buf, ")");
1073 switch (content->ocur) {
1074 case XML_ELEMENT_CONTENT_ONCE:
1075 break;
1076 case XML_ELEMENT_CONTENT_OPT:
1077 xmlBufferWriteChar(buf, "?");
1078 break;
1079 case XML_ELEMENT_CONTENT_MULT:
1080 xmlBufferWriteChar(buf, "*");
1081 break;
1082 case XML_ELEMENT_CONTENT_PLUS:
1083 xmlBufferWriteChar(buf, "+");
1084 break;
1085 }
1086}
1087
1088/**
1089 * xmlSprintfElementContent:
1090 * @buf: an output buffer
1091 * @content: An element table
1092 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1093 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001094 * Deprecated, unsafe, use xmlSnprintfElementContent
1095 */
1096void
1097xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1098 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1099 int glob ATTRIBUTE_UNUSED) {
1100}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001101#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001102
1103/**
1104 * xmlSnprintfElementContent:
1105 * @buf: an output buffer
1106 * @size: the buffer size
1107 * @content: An element table
1108 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1109 *
Owen Taylor3473f882001-02-23 17:55:21 +00001110 * This will dump the content of the element content definition
1111 * Intended just for the debug routine
1112 */
1113void
Daniel Veillardd3d06722001-08-15 12:06:36 +00001114xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int glob) {
1115 int len;
1116
Owen Taylor3473f882001-02-23 17:55:21 +00001117 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001118 len = strlen(buf);
1119 if (size - len < 50) {
1120 if ((size - len > 4) && (buf[len - 1] != '.'))
1121 strcat(buf, " ...");
1122 return;
1123 }
Owen Taylor3473f882001-02-23 17:55:21 +00001124 if (glob) strcat(buf, "(");
1125 switch (content->type) {
1126 case XML_ELEMENT_CONTENT_PCDATA:
1127 strcat(buf, "#PCDATA");
1128 break;
1129 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001130 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001131 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001132 strcat(buf, " ...");
1133 return;
1134 }
1135 strcat(buf, (char *) content->prefix);
1136 strcat(buf, ":");
1137 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001138 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001139 strcat(buf, " ...");
1140 return;
1141 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001142 if (content->name != NULL)
1143 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001144 break;
1145 case XML_ELEMENT_CONTENT_SEQ:
1146 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1147 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001148 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001149 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001150 xmlSnprintfElementContent(buf, size, content->c1, 0);
1151 len = strlen(buf);
1152 if (size - len < 50) {
1153 if ((size - len > 4) && (buf[len - 1] != '.'))
1154 strcat(buf, " ...");
1155 return;
1156 }
Owen Taylor3473f882001-02-23 17:55:21 +00001157 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001158 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1159 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1160 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001161 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001162 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001163 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001164 break;
1165 case XML_ELEMENT_CONTENT_OR:
1166 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1167 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001168 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001169 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001170 xmlSnprintfElementContent(buf, size, content->c1, 0);
1171 len = strlen(buf);
1172 if (size - len < 50) {
1173 if ((size - len > 4) && (buf[len - 1] != '.'))
1174 strcat(buf, " ...");
1175 return;
1176 }
Owen Taylor3473f882001-02-23 17:55:21 +00001177 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001178 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1179 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1180 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001181 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001182 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001183 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001184 break;
1185 }
1186 if (glob)
1187 strcat(buf, ")");
1188 switch (content->ocur) {
1189 case XML_ELEMENT_CONTENT_ONCE:
1190 break;
1191 case XML_ELEMENT_CONTENT_OPT:
1192 strcat(buf, "?");
1193 break;
1194 case XML_ELEMENT_CONTENT_MULT:
1195 strcat(buf, "*");
1196 break;
1197 case XML_ELEMENT_CONTENT_PLUS:
1198 strcat(buf, "+");
1199 break;
1200 }
1201}
1202
1203/****************************************************************
1204 * *
1205 * Registration of DTD declarations *
1206 * *
1207 ****************************************************************/
1208
1209/**
Owen Taylor3473f882001-02-23 17:55:21 +00001210 * xmlFreeElement:
1211 * @elem: An element
1212 *
1213 * Deallocate the memory used by an element definition
1214 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001215static void
Owen Taylor3473f882001-02-23 17:55:21 +00001216xmlFreeElement(xmlElementPtr elem) {
1217 if (elem == NULL) return;
1218 xmlUnlinkNode((xmlNodePtr) elem);
1219 xmlFreeElementContent(elem->content);
1220 if (elem->name != NULL)
1221 xmlFree((xmlChar *) elem->name);
1222 if (elem->prefix != NULL)
1223 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001224#ifdef LIBXML_REGEXP_ENABLED
1225 if (elem->contModel != NULL)
1226 xmlRegFreeRegexp(elem->contModel);
1227#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001228 xmlFree(elem);
1229}
1230
1231
1232/**
1233 * xmlAddElementDecl:
1234 * @ctxt: the validation context
1235 * @dtd: pointer to the DTD
1236 * @name: the entity name
1237 * @type: the element type
1238 * @content: the element content tree or NULL
1239 *
1240 * Register a new element declaration
1241 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001242 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001243 */
1244xmlElementPtr
William M. Brackedb65a72004-02-06 07:36:04 +00001245xmlAddElementDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001246 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001247 xmlElementTypeVal type,
1248 xmlElementContentPtr content) {
1249 xmlElementPtr ret;
1250 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001251 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001252 xmlChar *ns, *uqname;
1253
1254 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001255 return(NULL);
1256 }
1257 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001258 return(NULL);
1259 }
Daniel Veillard316a5c32005-01-23 22:56:39 +00001260
Owen Taylor3473f882001-02-23 17:55:21 +00001261 switch (type) {
1262 case XML_ELEMENT_TYPE_EMPTY:
1263 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001264 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1265 "xmlAddElementDecl: content != NULL for EMPTY\n",
1266 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001267 return(NULL);
1268 }
1269 break;
1270 case XML_ELEMENT_TYPE_ANY:
1271 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001272 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1273 "xmlAddElementDecl: content != NULL for ANY\n",
1274 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001275 return(NULL);
1276 }
1277 break;
1278 case XML_ELEMENT_TYPE_MIXED:
1279 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001280 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1281 "xmlAddElementDecl: content == NULL for MIXED\n",
1282 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001283 return(NULL);
1284 }
1285 break;
1286 case XML_ELEMENT_TYPE_ELEMENT:
1287 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001288 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1289 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1290 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001291 return(NULL);
1292 }
1293 break;
1294 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001295 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1296 "Internal: ELEMENT decl corrupted invalid type\n",
1297 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001298 return(NULL);
1299 }
1300
1301 /*
1302 * check if name is a QName
1303 */
1304 uqname = xmlSplitQName2(name, &ns);
1305 if (uqname != NULL)
1306 name = uqname;
1307
1308 /*
1309 * Create the Element table if needed.
1310 */
1311 table = (xmlElementTablePtr) dtd->elements;
1312 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00001313 xmlDictPtr dict = NULL;
1314
1315 if (dtd->doc != NULL)
1316 dict = dtd->doc->dict;
1317 table = xmlHashCreateDict(0, dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001318 dtd->elements = (void *) table;
1319 }
1320 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001321 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001322 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001323 if (uqname != NULL)
1324 xmlFree(uqname);
1325 if (ns != NULL)
1326 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001327 return(NULL);
1328 }
1329
Daniel Veillarda10efa82001-04-18 13:09:01 +00001330 /*
1331 * lookup old attributes inserted on an undefined element in the
1332 * internal subset.
1333 */
1334 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1335 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1336 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1337 oldAttributes = ret->attributes;
1338 ret->attributes = NULL;
1339 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1340 xmlFreeElement(ret);
1341 }
Owen Taylor3473f882001-02-23 17:55:21 +00001342 }
Owen Taylor3473f882001-02-23 17:55:21 +00001343
1344 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001345 * The element may already be present if one of its attribute
1346 * was registered first
1347 */
1348 ret = xmlHashLookup2(table, name, ns);
1349 if (ret != NULL) {
1350 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001351#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001352 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001353 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001354 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001355 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1356 "Redefinition of element %s\n",
1357 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001358#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001359 if (uqname != NULL)
1360 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001361 if (ns != NULL)
1362 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001363 return(NULL);
1364 }
1365 } else {
1366 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1367 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001368 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001369 if (uqname != NULL)
1370 xmlFree(uqname);
1371 if (ns != NULL)
1372 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001373 return(NULL);
1374 }
1375 memset(ret, 0, sizeof(xmlElement));
1376 ret->type = XML_ELEMENT_DECL;
1377
1378 /*
1379 * fill the structure.
1380 */
1381 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001382 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001383 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001384 if (uqname != NULL)
1385 xmlFree(uqname);
1386 if (ns != NULL)
1387 xmlFree(ns);
1388 xmlFree(ret);
1389 return(NULL);
1390 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001391 ret->prefix = ns;
1392
1393 /*
1394 * Validity Check:
1395 * Insertion must not fail
1396 */
1397 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001398#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001399 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001400 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001401 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001402 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1403 "Redefinition of element %s\n",
1404 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001405#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001406 xmlFreeElement(ret);
1407 if (uqname != NULL)
1408 xmlFree(uqname);
1409 return(NULL);
1410 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001411 /*
1412 * For new element, may have attributes from earlier
1413 * definition in internal subset
1414 */
1415 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001416 }
1417
1418 /*
1419 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001420 */
1421 ret->etype = type;
Owen Taylor3473f882001-02-23 17:55:21 +00001422 ret->content = xmlCopyElementContent(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001423
1424 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001425 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001426 */
1427 ret->parent = dtd;
1428 ret->doc = dtd->doc;
1429 if (dtd->last == NULL) {
1430 dtd->children = dtd->last = (xmlNodePtr) ret;
1431 } else {
1432 dtd->last->next = (xmlNodePtr) ret;
1433 ret->prev = dtd->last;
1434 dtd->last = (xmlNodePtr) ret;
1435 }
1436 if (uqname != NULL)
1437 xmlFree(uqname);
1438 return(ret);
1439}
1440
1441/**
1442 * xmlFreeElementTable:
1443 * @table: An element table
1444 *
1445 * Deallocate the memory used by an element hash table.
1446 */
1447void
1448xmlFreeElementTable(xmlElementTablePtr table) {
1449 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1450}
1451
Daniel Veillard652327a2003-09-29 18:02:38 +00001452#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001453/**
1454 * xmlCopyElement:
1455 * @elem: An element
1456 *
1457 * Build a copy of an element.
1458 *
1459 * Returns the new xmlElementPtr or NULL in case of error.
1460 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001461static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001462xmlCopyElement(xmlElementPtr elem) {
1463 xmlElementPtr cur;
1464
1465 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1466 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001467 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001468 return(NULL);
1469 }
1470 memset(cur, 0, sizeof(xmlElement));
1471 cur->type = XML_ELEMENT_DECL;
1472 cur->etype = elem->etype;
1473 if (elem->name != NULL)
1474 cur->name = xmlStrdup(elem->name);
1475 else
1476 cur->name = NULL;
1477 if (elem->prefix != NULL)
1478 cur->prefix = xmlStrdup(elem->prefix);
1479 else
1480 cur->prefix = NULL;
1481 cur->content = xmlCopyElementContent(elem->content);
1482 /* TODO : rebuild the attribute list on the copy */
1483 cur->attributes = NULL;
1484 return(cur);
1485}
1486
1487/**
1488 * xmlCopyElementTable:
1489 * @table: An element table
1490 *
1491 * Build a copy of an element table.
1492 *
1493 * Returns the new xmlElementTablePtr or NULL in case of error.
1494 */
1495xmlElementTablePtr
1496xmlCopyElementTable(xmlElementTablePtr table) {
1497 return((xmlElementTablePtr) xmlHashCopy(table,
1498 (xmlHashCopier) xmlCopyElement));
1499}
Daniel Veillard652327a2003-09-29 18:02:38 +00001500#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001501
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001502#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001503/**
1504 * xmlDumpElementDecl:
1505 * @buf: the XML buffer output
1506 * @elem: An element table
1507 *
1508 * This will dump the content of the element declaration as an XML
1509 * DTD definition
1510 */
1511void
1512xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001513 if ((buf == NULL) || (elem == NULL))
1514 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001515 switch (elem->etype) {
1516 case XML_ELEMENT_TYPE_EMPTY:
1517 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001518 if (elem->prefix != NULL) {
1519 xmlBufferWriteCHAR(buf, elem->prefix);
1520 xmlBufferWriteChar(buf, ":");
1521 }
Owen Taylor3473f882001-02-23 17:55:21 +00001522 xmlBufferWriteCHAR(buf, elem->name);
1523 xmlBufferWriteChar(buf, " EMPTY>\n");
1524 break;
1525 case XML_ELEMENT_TYPE_ANY:
1526 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001527 if (elem->prefix != NULL) {
1528 xmlBufferWriteCHAR(buf, elem->prefix);
1529 xmlBufferWriteChar(buf, ":");
1530 }
Owen Taylor3473f882001-02-23 17:55:21 +00001531 xmlBufferWriteCHAR(buf, elem->name);
1532 xmlBufferWriteChar(buf, " ANY>\n");
1533 break;
1534 case XML_ELEMENT_TYPE_MIXED:
1535 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001536 if (elem->prefix != NULL) {
1537 xmlBufferWriteCHAR(buf, elem->prefix);
1538 xmlBufferWriteChar(buf, ":");
1539 }
Owen Taylor3473f882001-02-23 17:55:21 +00001540 xmlBufferWriteCHAR(buf, elem->name);
1541 xmlBufferWriteChar(buf, " ");
1542 xmlDumpElementContent(buf, elem->content, 1);
1543 xmlBufferWriteChar(buf, ">\n");
1544 break;
1545 case XML_ELEMENT_TYPE_ELEMENT:
1546 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001547 if (elem->prefix != NULL) {
1548 xmlBufferWriteCHAR(buf, elem->prefix);
1549 xmlBufferWriteChar(buf, ":");
1550 }
Owen Taylor3473f882001-02-23 17:55:21 +00001551 xmlBufferWriteCHAR(buf, elem->name);
1552 xmlBufferWriteChar(buf, " ");
1553 xmlDumpElementContent(buf, elem->content, 1);
1554 xmlBufferWriteChar(buf, ">\n");
1555 break;
1556 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001557 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1558 "Internal: ELEMENT struct corrupted invalid type\n",
1559 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001560 }
1561}
1562
1563/**
William M. Brack9e660592003-10-20 14:56:06 +00001564 * xmlDumpElementDeclScan:
1565 * @elem: An element table
1566 * @buf: the XML buffer output
1567 *
1568 * This routine is used by the hash scan function. It just reverses
1569 * the arguments.
1570 */
1571static void
1572xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1573 xmlDumpElementDecl(buf, elem);
1574}
1575
1576/**
Owen Taylor3473f882001-02-23 17:55:21 +00001577 * xmlDumpElementTable:
1578 * @buf: the XML buffer output
1579 * @table: An element table
1580 *
1581 * This will dump the content of the element table as an XML DTD definition
1582 */
1583void
1584xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001585 if ((buf == NULL) || (table == NULL))
1586 return;
William M. Brack9e660592003-10-20 14:56:06 +00001587 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001588}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001589#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001590
1591/**
1592 * xmlCreateEnumeration:
1593 * @name: the enumeration name or NULL
1594 *
1595 * create and initialize an enumeration attribute node.
1596 *
1597 * Returns the xmlEnumerationPtr just created or NULL in case
1598 * of error.
1599 */
1600xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001601xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001602 xmlEnumerationPtr ret;
1603
1604 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1605 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001606 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001607 return(NULL);
1608 }
1609 memset(ret, 0, sizeof(xmlEnumeration));
1610
1611 if (name != NULL)
1612 ret->name = xmlStrdup(name);
1613 return(ret);
1614}
1615
1616/**
1617 * xmlFreeEnumeration:
1618 * @cur: the tree to free.
1619 *
1620 * free an enumeration attribute node (recursive).
1621 */
1622void
1623xmlFreeEnumeration(xmlEnumerationPtr cur) {
1624 if (cur == NULL) return;
1625
1626 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1627
1628 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001629 xmlFree(cur);
1630}
1631
Daniel Veillard652327a2003-09-29 18:02:38 +00001632#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001633/**
1634 * xmlCopyEnumeration:
1635 * @cur: the tree to copy.
1636 *
1637 * Copy an enumeration attribute node (recursive).
1638 *
1639 * Returns the xmlEnumerationPtr just created or NULL in case
1640 * of error.
1641 */
1642xmlEnumerationPtr
1643xmlCopyEnumeration(xmlEnumerationPtr cur) {
1644 xmlEnumerationPtr ret;
1645
1646 if (cur == NULL) return(NULL);
1647 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1648
1649 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1650 else ret->next = NULL;
1651
1652 return(ret);
1653}
Daniel Veillard652327a2003-09-29 18:02:38 +00001654#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001655
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001656#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001657/**
1658 * xmlDumpEnumeration:
1659 * @buf: the XML buffer output
1660 * @enum: An enumeration
1661 *
1662 * This will dump the content of the enumeration
1663 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001664static void
Owen Taylor3473f882001-02-23 17:55:21 +00001665xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001666 if ((buf == NULL) || (cur == NULL))
1667 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001668
1669 xmlBufferWriteCHAR(buf, cur->name);
1670 if (cur->next == NULL)
1671 xmlBufferWriteChar(buf, ")");
1672 else {
1673 xmlBufferWriteChar(buf, " | ");
1674 xmlDumpEnumeration(buf, cur->next);
1675 }
1676}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001677#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001678
Daniel Veillard4432df22003-09-28 18:58:27 +00001679#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001680/**
1681 * xmlScanAttributeDeclCallback:
1682 * @attr: the attribute decl
1683 * @list: the list to update
1684 *
1685 * Callback called by xmlScanAttributeDecl when a new attribute
1686 * has to be entered in the list.
1687 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001688static void
Owen Taylor3473f882001-02-23 17:55:21 +00001689xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001690 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001691 attr->nexth = *list;
1692 *list = attr;
1693}
1694
1695/**
1696 * xmlScanAttributeDecl:
1697 * @dtd: pointer to the DTD
1698 * @elem: the element name
1699 *
1700 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001701 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001702 *
1703 * Returns the pointer to the first attribute decl in the chain,
1704 * possibly NULL.
1705 */
1706xmlAttributePtr
1707xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1708 xmlAttributePtr ret = NULL;
1709 xmlAttributeTablePtr table;
1710
1711 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001712 return(NULL);
1713 }
1714 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001715 return(NULL);
1716 }
1717 table = (xmlAttributeTablePtr) dtd->attributes;
1718 if (table == NULL)
1719 return(NULL);
1720
1721 /* WRONG !!! */
1722 xmlHashScan3(table, NULL, NULL, elem,
1723 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1724 return(ret);
1725}
1726
1727/**
1728 * xmlScanIDAttributeDecl:
1729 * @ctxt: the validation context
1730 * @elem: the element name
1731 *
1732 * Verify that the element don't have too many ID attributes
1733 * declared.
1734 *
1735 * Returns the number of ID attributes found.
1736 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001737static int
Owen Taylor3473f882001-02-23 17:55:21 +00001738xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1739 xmlAttributePtr cur;
1740 int ret = 0;
1741
1742 if (elem == NULL) return(0);
1743 cur = elem->attributes;
1744 while (cur != NULL) {
1745 if (cur->atype == XML_ATTRIBUTE_ID) {
1746 ret ++;
1747 if (ret > 1)
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001748 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001749 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001750 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001751 }
1752 cur = cur->nexth;
1753 }
1754 return(ret);
1755}
Daniel Veillard4432df22003-09-28 18:58:27 +00001756#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001757
1758/**
1759 * xmlFreeAttribute:
1760 * @elem: An attribute
1761 *
1762 * Deallocate the memory used by an attribute definition
1763 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001764static void
Owen Taylor3473f882001-02-23 17:55:21 +00001765xmlFreeAttribute(xmlAttributePtr attr) {
1766 if (attr == NULL) return;
1767 xmlUnlinkNode((xmlNodePtr) attr);
1768 if (attr->tree != NULL)
1769 xmlFreeEnumeration(attr->tree);
1770 if (attr->elem != NULL)
1771 xmlFree((xmlChar *) attr->elem);
1772 if (attr->name != NULL)
1773 xmlFree((xmlChar *) attr->name);
1774 if (attr->defaultValue != NULL)
1775 xmlFree((xmlChar *) attr->defaultValue);
1776 if (attr->prefix != NULL)
1777 xmlFree((xmlChar *) attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001778 xmlFree(attr);
1779}
1780
1781
1782/**
1783 * xmlAddAttributeDecl:
1784 * @ctxt: the validation context
1785 * @dtd: pointer to the DTD
1786 * @elem: the element name
1787 * @name: the attribute name
1788 * @ns: the attribute namespace prefix
1789 * @type: the attribute type
1790 * @def: the attribute default type
1791 * @defaultValue: the attribute default value
1792 * @tree: if it's an enumeration, the associated list
1793 *
1794 * Register a new attribute declaration
1795 * Note that @tree becomes the ownership of the DTD
1796 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001797 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001798 */
1799xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001800xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001801 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001802 const xmlChar *name, const xmlChar *ns,
1803 xmlAttributeType type, xmlAttributeDefault def,
1804 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1805 xmlAttributePtr ret;
1806 xmlAttributeTablePtr table;
1807 xmlElementPtr elemDef;
1808
1809 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001810 xmlFreeEnumeration(tree);
1811 return(NULL);
1812 }
1813 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001814 xmlFreeEnumeration(tree);
1815 return(NULL);
1816 }
1817 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001818 xmlFreeEnumeration(tree);
1819 return(NULL);
1820 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001821
Daniel Veillard4432df22003-09-28 18:58:27 +00001822#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001823 /*
1824 * Check the type and possibly the default value.
1825 */
1826 switch (type) {
1827 case XML_ATTRIBUTE_CDATA:
1828 break;
1829 case XML_ATTRIBUTE_ID:
1830 break;
1831 case XML_ATTRIBUTE_IDREF:
1832 break;
1833 case XML_ATTRIBUTE_IDREFS:
1834 break;
1835 case XML_ATTRIBUTE_ENTITY:
1836 break;
1837 case XML_ATTRIBUTE_ENTITIES:
1838 break;
1839 case XML_ATTRIBUTE_NMTOKEN:
1840 break;
1841 case XML_ATTRIBUTE_NMTOKENS:
1842 break;
1843 case XML_ATTRIBUTE_ENUMERATION:
1844 break;
1845 case XML_ATTRIBUTE_NOTATION:
1846 break;
1847 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001848 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1849 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1850 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001851 xmlFreeEnumeration(tree);
1852 return(NULL);
1853 }
1854 if ((defaultValue != NULL) &&
1855 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001856 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1857 "Attribute %s of %s: invalid default value\n",
1858 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00001859 defaultValue = NULL;
Daniel Veillard42595322004-11-08 10:52:06 +00001860 if (ctxt != NULL)
1861 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001862 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001863#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001864
1865 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001866 * Check first that an attribute defined in the external subset wasn't
1867 * already defined in the internal subset
1868 */
1869 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1870 (dtd->doc->intSubset != NULL) &&
1871 (dtd->doc->intSubset->attributes != NULL)) {
1872 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1873 if (ret != NULL)
1874 return(NULL);
1875 }
1876
1877 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001878 * Create the Attribute table if needed.
1879 */
1880 table = (xmlAttributeTablePtr) dtd->attributes;
1881 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00001882 xmlDictPtr dict = NULL;
1883 if (dtd->doc != NULL)
1884 dict = dtd->doc->dict;
1885 table = xmlHashCreateDict(0, dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001886 dtd->attributes = (void *) table;
1887 }
1888 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001889 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001890 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001891 return(NULL);
1892 }
1893
1894
1895 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1896 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001897 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001898 return(NULL);
1899 }
1900 memset(ret, 0, sizeof(xmlAttribute));
1901 ret->type = XML_ATTRIBUTE_DECL;
1902
1903 /*
1904 * fill the structure.
1905 */
1906 ret->atype = type;
1907 ret->name = xmlStrdup(name);
1908 ret->prefix = xmlStrdup(ns);
1909 ret->elem = xmlStrdup(elem);
1910 ret->def = def;
1911 ret->tree = tree;
1912 if (defaultValue != NULL)
1913 ret->defaultValue = xmlStrdup(defaultValue);
1914
1915 /*
1916 * Validity Check:
1917 * Search the DTD for previous declarations of the ATTLIST
1918 */
1919 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001920#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001921 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001922 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00001923 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001924 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00001925 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001926 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001927#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001928 xmlFreeAttribute(ret);
1929 return(NULL);
1930 }
1931
1932 /*
1933 * Validity Check:
1934 * Multiple ID per element
1935 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001936 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001937 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00001938
Daniel Veillard4432df22003-09-28 18:58:27 +00001939#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001940 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00001941 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001942 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00001943 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001944 elem, name, NULL);
Daniel Veillard42595322004-11-08 10:52:06 +00001945 if (ctxt != NULL)
1946 ctxt->valid = 0;
Daniel Veillardc7612992002-02-17 22:47:37 +00001947 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001948#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00001949
Daniel Veillard48da9102001-08-07 01:10:10 +00001950 /*
1951 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001952 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00001953 */
1954 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1955 ((ret->prefix != NULL &&
1956 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1957 ret->nexth = elemDef->attributes;
1958 elemDef->attributes = ret;
1959 } else {
1960 xmlAttributePtr tmp = elemDef->attributes;
1961
1962 while ((tmp != NULL) &&
1963 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1964 ((ret->prefix != NULL &&
1965 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1966 if (tmp->nexth == NULL)
1967 break;
1968 tmp = tmp->nexth;
1969 }
1970 if (tmp != NULL) {
1971 ret->nexth = tmp->nexth;
1972 tmp->nexth = ret;
1973 } else {
1974 ret->nexth = elemDef->attributes;
1975 elemDef->attributes = ret;
1976 }
1977 }
Owen Taylor3473f882001-02-23 17:55:21 +00001978 }
1979
1980 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001981 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001982 */
1983 ret->parent = dtd;
1984 ret->doc = dtd->doc;
1985 if (dtd->last == NULL) {
1986 dtd->children = dtd->last = (xmlNodePtr) ret;
1987 } else {
1988 dtd->last->next = (xmlNodePtr) ret;
1989 ret->prev = dtd->last;
1990 dtd->last = (xmlNodePtr) ret;
1991 }
1992 return(ret);
1993}
1994
1995/**
1996 * xmlFreeAttributeTable:
1997 * @table: An attribute table
1998 *
1999 * Deallocate the memory used by an entities hash table.
2000 */
2001void
2002xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2003 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
2004}
2005
Daniel Veillard652327a2003-09-29 18:02:38 +00002006#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002007/**
2008 * xmlCopyAttribute:
2009 * @attr: An attribute
2010 *
2011 * Build a copy of an attribute.
2012 *
2013 * Returns the new xmlAttributePtr or NULL in case of error.
2014 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002015static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002016xmlCopyAttribute(xmlAttributePtr attr) {
2017 xmlAttributePtr cur;
2018
2019 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2020 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002021 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002022 return(NULL);
2023 }
2024 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00002025 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00002026 cur->atype = attr->atype;
2027 cur->def = attr->def;
2028 cur->tree = xmlCopyEnumeration(attr->tree);
2029 if (attr->elem != NULL)
2030 cur->elem = xmlStrdup(attr->elem);
2031 if (attr->name != NULL)
2032 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002033 if (attr->prefix != NULL)
2034 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002035 if (attr->defaultValue != NULL)
2036 cur->defaultValue = xmlStrdup(attr->defaultValue);
2037 return(cur);
2038}
2039
2040/**
2041 * xmlCopyAttributeTable:
2042 * @table: An attribute table
2043 *
2044 * Build a copy of an attribute table.
2045 *
2046 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2047 */
2048xmlAttributeTablePtr
2049xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2050 return((xmlAttributeTablePtr) xmlHashCopy(table,
2051 (xmlHashCopier) xmlCopyAttribute));
2052}
Daniel Veillard652327a2003-09-29 18:02:38 +00002053#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002054
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002055#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002056/**
2057 * xmlDumpAttributeDecl:
2058 * @buf: the XML buffer output
2059 * @attr: An attribute declaration
2060 *
2061 * This will dump the content of the attribute declaration as an XML
2062 * DTD definition
2063 */
2064void
2065xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002066 if ((buf == NULL) || (attr == NULL))
2067 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002068 xmlBufferWriteChar(buf, "<!ATTLIST ");
2069 xmlBufferWriteCHAR(buf, attr->elem);
2070 xmlBufferWriteChar(buf, " ");
2071 if (attr->prefix != NULL) {
2072 xmlBufferWriteCHAR(buf, attr->prefix);
2073 xmlBufferWriteChar(buf, ":");
2074 }
2075 xmlBufferWriteCHAR(buf, attr->name);
2076 switch (attr->atype) {
2077 case XML_ATTRIBUTE_CDATA:
2078 xmlBufferWriteChar(buf, " CDATA");
2079 break;
2080 case XML_ATTRIBUTE_ID:
2081 xmlBufferWriteChar(buf, " ID");
2082 break;
2083 case XML_ATTRIBUTE_IDREF:
2084 xmlBufferWriteChar(buf, " IDREF");
2085 break;
2086 case XML_ATTRIBUTE_IDREFS:
2087 xmlBufferWriteChar(buf, " IDREFS");
2088 break;
2089 case XML_ATTRIBUTE_ENTITY:
2090 xmlBufferWriteChar(buf, " ENTITY");
2091 break;
2092 case XML_ATTRIBUTE_ENTITIES:
2093 xmlBufferWriteChar(buf, " ENTITIES");
2094 break;
2095 case XML_ATTRIBUTE_NMTOKEN:
2096 xmlBufferWriteChar(buf, " NMTOKEN");
2097 break;
2098 case XML_ATTRIBUTE_NMTOKENS:
2099 xmlBufferWriteChar(buf, " NMTOKENS");
2100 break;
2101 case XML_ATTRIBUTE_ENUMERATION:
2102 xmlBufferWriteChar(buf, " (");
2103 xmlDumpEnumeration(buf, attr->tree);
2104 break;
2105 case XML_ATTRIBUTE_NOTATION:
2106 xmlBufferWriteChar(buf, " NOTATION (");
2107 xmlDumpEnumeration(buf, attr->tree);
2108 break;
2109 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002110 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2111 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2112 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002113 }
2114 switch (attr->def) {
2115 case XML_ATTRIBUTE_NONE:
2116 break;
2117 case XML_ATTRIBUTE_REQUIRED:
2118 xmlBufferWriteChar(buf, " #REQUIRED");
2119 break;
2120 case XML_ATTRIBUTE_IMPLIED:
2121 xmlBufferWriteChar(buf, " #IMPLIED");
2122 break;
2123 case XML_ATTRIBUTE_FIXED:
2124 xmlBufferWriteChar(buf, " #FIXED");
2125 break;
2126 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002127 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2128 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2129 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002130 }
2131 if (attr->defaultValue != NULL) {
2132 xmlBufferWriteChar(buf, " ");
2133 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2134 }
2135 xmlBufferWriteChar(buf, ">\n");
2136}
2137
2138/**
William M. Brack9e660592003-10-20 14:56:06 +00002139 * xmlDumpAttributeDeclScan:
2140 * @attr: An attribute declaration
2141 * @buf: the XML buffer output
2142 *
2143 * This is used with the hash scan function - just reverses arguments
2144 */
2145static void
2146xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2147 xmlDumpAttributeDecl(buf, attr);
2148}
2149
2150/**
Owen Taylor3473f882001-02-23 17:55:21 +00002151 * xmlDumpAttributeTable:
2152 * @buf: the XML buffer output
2153 * @table: An attribute table
2154 *
2155 * This will dump the content of the attribute table as an XML DTD definition
2156 */
2157void
2158xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002159 if ((buf == NULL) || (table == NULL))
2160 return;
William M. Brack9e660592003-10-20 14:56:06 +00002161 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002162}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002163#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002164
2165/************************************************************************
2166 * *
2167 * NOTATIONs *
2168 * *
2169 ************************************************************************/
2170/**
Owen Taylor3473f882001-02-23 17:55:21 +00002171 * xmlFreeNotation:
2172 * @not: A notation
2173 *
2174 * Deallocate the memory used by an notation definition
2175 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002176static void
Owen Taylor3473f882001-02-23 17:55:21 +00002177xmlFreeNotation(xmlNotationPtr nota) {
2178 if (nota == NULL) return;
2179 if (nota->name != NULL)
2180 xmlFree((xmlChar *) nota->name);
2181 if (nota->PublicID != NULL)
2182 xmlFree((xmlChar *) nota->PublicID);
2183 if (nota->SystemID != NULL)
2184 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002185 xmlFree(nota);
2186}
2187
2188
2189/**
2190 * xmlAddNotationDecl:
2191 * @dtd: pointer to the DTD
2192 * @ctxt: the validation context
2193 * @name: the entity name
2194 * @PublicID: the public identifier or NULL
2195 * @SystemID: the system identifier or NULL
2196 *
2197 * Register a new notation declaration
2198 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002199 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002200 */
2201xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002202xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002203 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002204 const xmlChar *PublicID, const xmlChar *SystemID) {
2205 xmlNotationPtr ret;
2206 xmlNotationTablePtr table;
2207
2208 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002209 return(NULL);
2210 }
2211 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002212 return(NULL);
2213 }
2214 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002215 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002216 }
2217
2218 /*
2219 * Create the Notation table if needed.
2220 */
2221 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002222 if (table == NULL) {
2223 xmlDictPtr dict = NULL;
2224 if (dtd->doc != NULL)
2225 dict = dtd->doc->dict;
2226
2227 dtd->notations = table = xmlHashCreateDict(0, dict);
2228 }
Owen Taylor3473f882001-02-23 17:55:21 +00002229 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002230 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002231 "xmlAddNotationDecl: Table creation failed!\n");
2232 return(NULL);
2233 }
2234
2235 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2236 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002237 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002238 return(NULL);
2239 }
2240 memset(ret, 0, sizeof(xmlNotation));
2241
2242 /*
2243 * fill the structure.
2244 */
2245 ret->name = xmlStrdup(name);
2246 if (SystemID != NULL)
2247 ret->SystemID = xmlStrdup(SystemID);
2248 if (PublicID != NULL)
2249 ret->PublicID = xmlStrdup(PublicID);
2250
2251 /*
2252 * Validity Check:
2253 * Check the DTD for previous declarations of the ATTLIST
2254 */
2255 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002256#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002257 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2258 "xmlAddNotationDecl: %s already defined\n",
2259 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002260#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002261 xmlFreeNotation(ret);
2262 return(NULL);
2263 }
2264 return(ret);
2265}
2266
2267/**
2268 * xmlFreeNotationTable:
2269 * @table: An notation table
2270 *
2271 * Deallocate the memory used by an entities hash table.
2272 */
2273void
2274xmlFreeNotationTable(xmlNotationTablePtr table) {
2275 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2276}
2277
Daniel Veillard652327a2003-09-29 18:02:38 +00002278#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002279/**
2280 * xmlCopyNotation:
2281 * @nota: A notation
2282 *
2283 * Build a copy of a notation.
2284 *
2285 * Returns the new xmlNotationPtr or NULL in case of error.
2286 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002287static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002288xmlCopyNotation(xmlNotationPtr nota) {
2289 xmlNotationPtr cur;
2290
2291 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2292 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002293 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002294 return(NULL);
2295 }
2296 if (nota->name != NULL)
2297 cur->name = xmlStrdup(nota->name);
2298 else
2299 cur->name = NULL;
2300 if (nota->PublicID != NULL)
2301 cur->PublicID = xmlStrdup(nota->PublicID);
2302 else
2303 cur->PublicID = NULL;
2304 if (nota->SystemID != NULL)
2305 cur->SystemID = xmlStrdup(nota->SystemID);
2306 else
2307 cur->SystemID = NULL;
2308 return(cur);
2309}
2310
2311/**
2312 * xmlCopyNotationTable:
2313 * @table: A notation table
2314 *
2315 * Build a copy of a notation table.
2316 *
2317 * Returns the new xmlNotationTablePtr or NULL in case of error.
2318 */
2319xmlNotationTablePtr
2320xmlCopyNotationTable(xmlNotationTablePtr table) {
2321 return((xmlNotationTablePtr) xmlHashCopy(table,
2322 (xmlHashCopier) xmlCopyNotation));
2323}
Daniel Veillard652327a2003-09-29 18:02:38 +00002324#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002325
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002326#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002327/**
2328 * xmlDumpNotationDecl:
2329 * @buf: the XML buffer output
2330 * @nota: A notation declaration
2331 *
2332 * This will dump the content the notation declaration as an XML DTD definition
2333 */
2334void
2335xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002336 if ((buf == NULL) || (nota == NULL))
2337 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002338 xmlBufferWriteChar(buf, "<!NOTATION ");
2339 xmlBufferWriteCHAR(buf, nota->name);
2340 if (nota->PublicID != NULL) {
2341 xmlBufferWriteChar(buf, " PUBLIC ");
2342 xmlBufferWriteQuotedString(buf, nota->PublicID);
2343 if (nota->SystemID != NULL) {
2344 xmlBufferWriteChar(buf, " ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002345 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002346 }
2347 } else {
2348 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002349 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002350 }
2351 xmlBufferWriteChar(buf, " >\n");
2352}
2353
2354/**
William M. Brack9e660592003-10-20 14:56:06 +00002355 * xmlDumpNotationDeclScan:
2356 * @nota: A notation declaration
2357 * @buf: the XML buffer output
2358 *
2359 * This is called with the hash scan function, and just reverses args
2360 */
2361static void
2362xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2363 xmlDumpNotationDecl(buf, nota);
2364}
2365
2366/**
Owen Taylor3473f882001-02-23 17:55:21 +00002367 * xmlDumpNotationTable:
2368 * @buf: the XML buffer output
2369 * @table: A notation table
2370 *
2371 * This will dump the content of the notation table as an XML DTD definition
2372 */
2373void
2374xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002375 if ((buf == NULL) || (table == NULL))
2376 return;
William M. Brack9e660592003-10-20 14:56:06 +00002377 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002378}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002379#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002380
2381/************************************************************************
2382 * *
2383 * IDs *
2384 * *
2385 ************************************************************************/
2386/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002387 * DICT_FREE:
2388 * @str: a string
2389 *
2390 * Free a string if it is not owned by the "dict" dictionnary in the
2391 * current scope
2392 */
2393#define DICT_FREE(str) \
2394 if ((str) && ((!dict) || \
2395 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2396 xmlFree((char *)(str));
2397
2398/**
Owen Taylor3473f882001-02-23 17:55:21 +00002399 * xmlFreeID:
2400 * @not: A id
2401 *
2402 * Deallocate the memory used by an id definition
2403 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002404static void
Owen Taylor3473f882001-02-23 17:55:21 +00002405xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002406 xmlDictPtr dict = NULL;
2407
Owen Taylor3473f882001-02-23 17:55:21 +00002408 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002409
2410 if (id->doc != NULL)
2411 dict = id->doc->dict;
2412
Owen Taylor3473f882001-02-23 17:55:21 +00002413 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002414 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002415 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002416 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002417 xmlFree(id);
2418}
2419
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002420
Owen Taylor3473f882001-02-23 17:55:21 +00002421/**
2422 * xmlAddID:
2423 * @ctxt: the validation context
2424 * @doc: pointer to the document
2425 * @value: the value name
2426 * @attr: the attribute holding the ID
2427 *
2428 * Register a new id declaration
2429 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002430 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002431 */
2432xmlIDPtr
2433xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2434 xmlAttrPtr attr) {
2435 xmlIDPtr ret;
2436 xmlIDTablePtr table;
2437
2438 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002439 return(NULL);
2440 }
2441 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002442 return(NULL);
2443 }
2444 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002445 return(NULL);
2446 }
2447
2448 /*
2449 * Create the ID table if needed.
2450 */
2451 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002452 if (table == NULL) {
2453 doc->ids = table = xmlHashCreateDict(0, doc->dict);
2454 }
Owen Taylor3473f882001-02-23 17:55:21 +00002455 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002456 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002457 "xmlAddID: Table creation failed!\n");
2458 return(NULL);
2459 }
2460
2461 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2462 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002463 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002464 return(NULL);
2465 }
2466
2467 /*
2468 * fill the structure.
2469 */
2470 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002471 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002472 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2473 /*
2474 * Operating in streaming mode, attr is gonna disapear
2475 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002476 if (doc->dict != NULL)
2477 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2478 else
2479 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002480 ret->attr = NULL;
2481 } else {
2482 ret->attr = attr;
2483 ret->name = NULL;
2484 }
2485 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002486
2487 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002488#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002489 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002490 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002491 */
Daniel Veillardd3669b22004-02-25 12:34:55 +00002492 if ((ctxt != NULL) && (ctxt->error != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002493 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2494 "ID %s already defined\n",
2495 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002496 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002497#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002498 xmlFreeID(ret);
2499 return(NULL);
2500 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002501 if (attr != NULL)
2502 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002503 return(ret);
2504}
2505
2506/**
2507 * xmlFreeIDTable:
2508 * @table: An id table
2509 *
2510 * Deallocate the memory used by an ID hash table.
2511 */
2512void
2513xmlFreeIDTable(xmlIDTablePtr table) {
2514 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2515}
2516
2517/**
2518 * xmlIsID:
2519 * @doc: the document
2520 * @elem: the element carrying the attribute
2521 * @attr: the attribute
2522 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002523 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002524 * then this is done if DTD loading has been requested. In the case
2525 * of HTML documents parsed with the HTML parser, then ID detection is
2526 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002527 *
2528 * Returns 0 or 1 depending on the lookup result
2529 */
2530int
2531xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2532 if (doc == NULL) return(0);
2533 if (attr == NULL) return(0);
2534 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2535 return(0);
2536 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard9ba8e382003-10-28 21:31:45 +00002537 if (((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2538 (xmlStrEqual(BAD_CAST "name", attr->name))) &&
2539 ((elem != NULL) && (!xmlStrEqual(elem->name, BAD_CAST "input"))))
Owen Taylor3473f882001-02-23 17:55:21 +00002540 return(1);
2541 return(0);
2542 } else {
2543 xmlAttributePtr attrDecl;
2544
2545 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002546 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002547 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002548 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002549
2550 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002551 if (fullname == NULL)
2552 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002553 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2554 attr->name);
2555 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2556 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2557 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002558 if ((fullname != fn) && (fullname != elem->name))
2559 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002560 } else {
2561 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2562 attr->name);
2563 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2564 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2565 attr->name);
2566 }
Owen Taylor3473f882001-02-23 17:55:21 +00002567
2568 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2569 return(1);
2570 }
2571 return(0);
2572}
2573
2574/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002575 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002576 * @doc: the document
2577 * @attr: the attribute
2578 *
2579 * Remove the given attribute from the ID table maintained internally.
2580 *
2581 * Returns -1 if the lookup failed and 0 otherwise
2582 */
2583int
2584xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002585 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002586 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002587 xmlChar *ID;
2588
2589 if (doc == NULL) return(-1);
2590 if (attr == NULL) return(-1);
2591 table = (xmlIDTablePtr) doc->ids;
2592 if (table == NULL)
2593 return(-1);
2594
2595 if (attr == NULL)
2596 return(-1);
2597 ID = xmlNodeListGetString(doc, attr->children, 1);
2598 if (ID == NULL)
2599 return(-1);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002600 id = xmlHashLookup(table, ID);
2601 if (id == NULL || id->attr != attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002602 xmlFree(ID);
2603 return(-1);
2604 }
Daniel Veillard91b955c2004-12-10 10:26:42 +00002605 xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID);
Owen Taylor3473f882001-02-23 17:55:21 +00002606 xmlFree(ID);
2607 return(0);
2608}
2609
2610/**
2611 * xmlGetID:
2612 * @doc: pointer to the document
2613 * @ID: the ID value
2614 *
2615 * Search the attribute declaring the given ID
2616 *
2617 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2618 */
2619xmlAttrPtr
2620xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2621 xmlIDTablePtr table;
2622 xmlIDPtr id;
2623
2624 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002625 return(NULL);
2626 }
2627
2628 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002629 return(NULL);
2630 }
2631
2632 table = (xmlIDTablePtr) doc->ids;
2633 if (table == NULL)
2634 return(NULL);
2635
2636 id = xmlHashLookup(table, ID);
2637 if (id == NULL)
2638 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002639 if (id->attr == NULL) {
2640 /*
2641 * We are operating on a stream, return a well known reference
2642 * since the attribute node doesn't exist anymore
2643 */
2644 return((xmlAttrPtr) doc);
2645 }
Owen Taylor3473f882001-02-23 17:55:21 +00002646 return(id->attr);
2647}
2648
2649/************************************************************************
2650 * *
2651 * Refs *
2652 * *
2653 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002654typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002655{
2656 xmlListPtr l;
2657 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002658} xmlRemoveMemo;
2659
2660typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2661
2662typedef struct xmlValidateMemo_t
2663{
2664 xmlValidCtxtPtr ctxt;
2665 const xmlChar *name;
2666} xmlValidateMemo;
2667
2668typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002669
2670/**
Owen Taylor3473f882001-02-23 17:55:21 +00002671 * xmlFreeRef:
2672 * @lk: A list link
2673 *
2674 * Deallocate the memory used by a ref definition
2675 */
2676static void
2677xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002678 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2679 if (ref == NULL) return;
2680 if (ref->value != NULL)
2681 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002682 if (ref->name != NULL)
2683 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002684 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002685}
2686
2687/**
2688 * xmlFreeRefList:
2689 * @list_ref: A list of references.
2690 *
2691 * Deallocate the memory used by a list of references
2692 */
2693static void
2694xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002695 if (list_ref == NULL) return;
2696 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002697}
2698
2699/**
2700 * xmlWalkRemoveRef:
2701 * @data: Contents of current link
2702 * @user: Value supplied by the user
2703 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002704 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002705 */
2706static int
2707xmlWalkRemoveRef(const void *data, const void *user)
2708{
Daniel Veillard37721922001-05-04 15:21:12 +00002709 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2710 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2711 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002712
Daniel Veillard37721922001-05-04 15:21:12 +00002713 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2714 xmlListRemoveFirst(ref_list, (void *)data);
2715 return 0;
2716 }
2717 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002718}
2719
2720/**
Daniel Veillard770075b2004-02-25 10:44:30 +00002721 * xmlDummyCompare
2722 * @data0: Value supplied by the user
2723 * @data1: Value supplied by the user
2724 *
2725 * Do nothing, return 0. Used to create unordered lists.
2726 */
2727static int
Daniel Veillardf54cd532004-02-25 11:52:31 +00002728xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2729 const void *data1 ATTRIBUTE_UNUSED)
Daniel Veillard770075b2004-02-25 10:44:30 +00002730{
2731 return (0);
2732}
2733
2734/**
Owen Taylor3473f882001-02-23 17:55:21 +00002735 * xmlAddRef:
2736 * @ctxt: the validation context
2737 * @doc: pointer to the document
2738 * @value: the value name
2739 * @attr: the attribute holding the Ref
2740 *
2741 * Register a new ref declaration
2742 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002743 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002744 */
2745xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002746xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002747 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002748 xmlRefPtr ret;
2749 xmlRefTablePtr table;
2750 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002751
Daniel Veillard37721922001-05-04 15:21:12 +00002752 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002753 return(NULL);
2754 }
2755 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002756 return(NULL);
2757 }
2758 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002759 return(NULL);
2760 }
Owen Taylor3473f882001-02-23 17:55:21 +00002761
Daniel Veillard37721922001-05-04 15:21:12 +00002762 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002763 * Create the Ref table if needed.
2764 */
Daniel Veillard37721922001-05-04 15:21:12 +00002765 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002766 if (table == NULL) {
2767 doc->refs = table = xmlHashCreateDict(0, doc->dict);
2768 }
Daniel Veillard37721922001-05-04 15:21:12 +00002769 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002770 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002771 "xmlAddRef: Table creation failed!\n");
2772 return(NULL);
2773 }
Owen Taylor3473f882001-02-23 17:55:21 +00002774
Daniel Veillard37721922001-05-04 15:21:12 +00002775 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2776 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002777 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002778 return(NULL);
2779 }
Owen Taylor3473f882001-02-23 17:55:21 +00002780
Daniel Veillard37721922001-05-04 15:21:12 +00002781 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002782 * fill the structure.
2783 */
Daniel Veillard37721922001-05-04 15:21:12 +00002784 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002785 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2786 /*
2787 * Operating in streaming mode, attr is gonna disapear
2788 */
2789 ret->name = xmlStrdup(attr->name);
2790 ret->attr = NULL;
2791 } else {
2792 ret->name = NULL;
2793 ret->attr = attr;
2794 }
2795 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002796
Daniel Veillard37721922001-05-04 15:21:12 +00002797 /* To add a reference :-
2798 * References are maintained as a list of references,
2799 * Lookup the entry, if no entry create new nodelist
2800 * Add the owning node to the NodeList
2801 * Return the ref
2802 */
Owen Taylor3473f882001-02-23 17:55:21 +00002803
Daniel Veillard37721922001-05-04 15:21:12 +00002804 if (NULL == (ref_list = xmlHashLookup(table, value))) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002805 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002806 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2807 "xmlAddRef: Reference list creation failed!\n",
2808 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002809 return(NULL);
2810 }
2811 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2812 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002813 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2814 "xmlAddRef: Reference list insertion failed!\n",
2815 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002816 return(NULL);
2817 }
2818 }
Daniel Veillard965983a2004-02-17 16:30:24 +00002819/* xmlListInsert(ref_list, ret); */
2820 xmlListAppend(ref_list, ret);
Daniel Veillard37721922001-05-04 15:21:12 +00002821 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002822}
2823
2824/**
2825 * xmlFreeRefTable:
2826 * @table: An ref table
2827 *
2828 * Deallocate the memory used by an Ref hash table.
2829 */
2830void
2831xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002832 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002833}
2834
2835/**
2836 * xmlIsRef:
2837 * @doc: the document
2838 * @elem: the element carrying the attribute
2839 * @attr: the attribute
2840 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002841 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00002842 * then this is simple, otherwise we use an heuristic: name Ref (upper
2843 * or lowercase).
2844 *
2845 * Returns 0 or 1 depending on the lookup result
2846 */
2847int
2848xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00002849 if (attr == NULL)
2850 return(0);
2851 if (doc == NULL) {
2852 doc = attr->doc;
2853 if (doc == NULL) return(0);
2854 }
2855
Daniel Veillard37721922001-05-04 15:21:12 +00002856 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2857 return(0);
2858 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2859 /* TODO @@@ */
2860 return(0);
2861 } else {
2862 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00002863
Daniel Veillardce244ad2004-11-05 10:03:46 +00002864 if (elem == NULL) return(0);
Daniel Veillard37721922001-05-04 15:21:12 +00002865 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2866 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2867 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2868 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002869
Daniel Veillard37721922001-05-04 15:21:12 +00002870 if ((attrDecl != NULL) &&
2871 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2872 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2873 return(1);
2874 }
2875 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002876}
2877
2878/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002879 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00002880 * @doc: the document
2881 * @attr: the attribute
2882 *
2883 * Remove the given attribute from the Ref table maintained internally.
2884 *
2885 * Returns -1 if the lookup failed and 0 otherwise
2886 */
2887int
2888xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002889 xmlListPtr ref_list;
2890 xmlRefTablePtr table;
2891 xmlChar *ID;
2892 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00002893
Daniel Veillard37721922001-05-04 15:21:12 +00002894 if (doc == NULL) return(-1);
2895 if (attr == NULL) return(-1);
2896 table = (xmlRefTablePtr) doc->refs;
2897 if (table == NULL)
2898 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002899
Daniel Veillard37721922001-05-04 15:21:12 +00002900 if (attr == NULL)
2901 return(-1);
2902 ID = xmlNodeListGetString(doc, attr->children, 1);
2903 if (ID == NULL)
2904 return(-1);
2905 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00002906
Daniel Veillard37721922001-05-04 15:21:12 +00002907 if(ref_list == NULL) {
2908 xmlFree(ID);
2909 return (-1);
2910 }
2911 /* At this point, ref_list refers to a list of references which
2912 * have the same key as the supplied attr. Our list of references
2913 * is ordered by reference address and we don't have that information
2914 * here to use when removing. We'll have to walk the list and
2915 * check for a matching attribute, when we find one stop the walk
2916 * and remove the entry.
2917 * The list is ordered by reference, so that means we don't have the
2918 * key. Passing the list and the reference to the walker means we
2919 * will have enough data to be able to remove the entry.
2920 */
2921 target.l = ref_list;
2922 target.ap = attr;
2923
2924 /* Remove the supplied attr from our list */
2925 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00002926
Daniel Veillard37721922001-05-04 15:21:12 +00002927 /*If the list is empty then remove the list entry in the hash */
2928 if (xmlListEmpty(ref_list))
2929 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2930 xmlFreeRefList);
2931 xmlFree(ID);
2932 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002933}
2934
2935/**
2936 * xmlGetRefs:
2937 * @doc: pointer to the document
2938 * @ID: the ID value
2939 *
2940 * Find the set of references for the supplied ID.
2941 *
2942 * Returns NULL if not found, otherwise node set for the ID.
2943 */
2944xmlListPtr
2945xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00002946 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00002947
Daniel Veillard37721922001-05-04 15:21:12 +00002948 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002949 return(NULL);
2950 }
Owen Taylor3473f882001-02-23 17:55:21 +00002951
Daniel Veillard37721922001-05-04 15:21:12 +00002952 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002953 return(NULL);
2954 }
Owen Taylor3473f882001-02-23 17:55:21 +00002955
Daniel Veillard37721922001-05-04 15:21:12 +00002956 table = (xmlRefTablePtr) doc->refs;
2957 if (table == NULL)
2958 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002959
Daniel Veillard37721922001-05-04 15:21:12 +00002960 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00002961}
2962
2963/************************************************************************
2964 * *
2965 * Routines for validity checking *
2966 * *
2967 ************************************************************************/
2968
2969/**
2970 * xmlGetDtdElementDesc:
2971 * @dtd: a pointer to the DtD to search
2972 * @name: the element name
2973 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002974 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002975 *
2976 * returns the xmlElementPtr if found or NULL
2977 */
2978
2979xmlElementPtr
2980xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2981 xmlElementTablePtr table;
2982 xmlElementPtr cur;
2983 xmlChar *uqname = NULL, *prefix = NULL;
2984
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002985 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002986 if (dtd->elements == NULL)
2987 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002988 table = (xmlElementTablePtr) dtd->elements;
2989
2990 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002991 if (uqname != NULL)
2992 name = uqname;
2993 cur = xmlHashLookup2(table, name, prefix);
2994 if (prefix != NULL) xmlFree(prefix);
2995 if (uqname != NULL) xmlFree(uqname);
2996 return(cur);
2997}
2998/**
2999 * xmlGetDtdElementDesc2:
3000 * @dtd: a pointer to the DtD to search
3001 * @name: the element name
3002 * @create: create an empty description if not found
3003 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003004 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00003005 *
3006 * returns the xmlElementPtr if found or NULL
3007 */
3008
Daniel Veillard86fd5a72001-12-13 14:55:21 +00003009static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00003010xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3011 xmlElementTablePtr table;
3012 xmlElementPtr cur;
3013 xmlChar *uqname = NULL, *prefix = NULL;
3014
3015 if (dtd == NULL) return(NULL);
3016 if (dtd->elements == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003017 xmlDictPtr dict = NULL;
3018
3019 if (dtd->doc != NULL)
3020 dict = dtd->doc->dict;
3021
Daniel Veillarda10efa82001-04-18 13:09:01 +00003022 if (!create)
3023 return(NULL);
3024 /*
3025 * Create the Element table if needed.
3026 */
3027 table = (xmlElementTablePtr) dtd->elements;
3028 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003029 table = xmlHashCreateDict(0, dict);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003030 dtd->elements = (void *) table;
3031 }
3032 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003033 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003034 return(NULL);
3035 }
3036 }
3037 table = (xmlElementTablePtr) dtd->elements;
3038
3039 uqname = xmlSplitQName2(name, &prefix);
3040 if (uqname != NULL)
3041 name = uqname;
3042 cur = xmlHashLookup2(table, name, prefix);
3043 if ((cur == NULL) && (create)) {
3044 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3045 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003046 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003047 return(NULL);
3048 }
3049 memset(cur, 0, sizeof(xmlElement));
3050 cur->type = XML_ELEMENT_DECL;
3051
3052 /*
3053 * fill the structure.
3054 */
3055 cur->name = xmlStrdup(name);
3056 cur->prefix = xmlStrdup(prefix);
3057 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3058
3059 xmlHashAddEntry2(table, name, prefix, cur);
3060 }
3061 if (prefix != NULL) xmlFree(prefix);
3062 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003063 return(cur);
3064}
3065
3066/**
3067 * xmlGetDtdQElementDesc:
3068 * @dtd: a pointer to the DtD to search
3069 * @name: the element name
3070 * @prefix: the element namespace prefix
3071 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003072 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003073 *
3074 * returns the xmlElementPtr if found or NULL
3075 */
3076
Daniel Veillard48da9102001-08-07 01:10:10 +00003077xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003078xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3079 const xmlChar *prefix) {
3080 xmlElementTablePtr table;
3081
3082 if (dtd == NULL) return(NULL);
3083 if (dtd->elements == NULL) return(NULL);
3084 table = (xmlElementTablePtr) dtd->elements;
3085
3086 return(xmlHashLookup2(table, name, prefix));
3087}
3088
3089/**
3090 * xmlGetDtdAttrDesc:
3091 * @dtd: a pointer to the DtD to search
3092 * @elem: the element name
3093 * @name: the attribute name
3094 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003095 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003096 * this element.
3097 *
3098 * returns the xmlAttributePtr if found or NULL
3099 */
3100
3101xmlAttributePtr
3102xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3103 xmlAttributeTablePtr table;
3104 xmlAttributePtr cur;
3105 xmlChar *uqname = NULL, *prefix = NULL;
3106
3107 if (dtd == NULL) return(NULL);
3108 if (dtd->attributes == NULL) return(NULL);
3109
3110 table = (xmlAttributeTablePtr) dtd->attributes;
3111 if (table == NULL)
3112 return(NULL);
3113
3114 uqname = xmlSplitQName2(name, &prefix);
3115
3116 if (uqname != NULL) {
3117 cur = xmlHashLookup3(table, uqname, prefix, elem);
3118 if (prefix != NULL) xmlFree(prefix);
3119 if (uqname != NULL) xmlFree(uqname);
3120 } else
3121 cur = xmlHashLookup3(table, name, NULL, elem);
3122 return(cur);
3123}
3124
3125/**
3126 * xmlGetDtdQAttrDesc:
3127 * @dtd: a pointer to the DtD to search
3128 * @elem: the element name
3129 * @name: the attribute name
3130 * @prefix: the attribute namespace prefix
3131 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003132 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003133 * this element.
3134 *
3135 * returns the xmlAttributePtr if found or NULL
3136 */
3137
Daniel Veillard48da9102001-08-07 01:10:10 +00003138xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003139xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3140 const xmlChar *prefix) {
3141 xmlAttributeTablePtr table;
3142
3143 if (dtd == NULL) return(NULL);
3144 if (dtd->attributes == NULL) return(NULL);
3145 table = (xmlAttributeTablePtr) dtd->attributes;
3146
3147 return(xmlHashLookup3(table, name, prefix, elem));
3148}
3149
3150/**
3151 * xmlGetDtdNotationDesc:
3152 * @dtd: a pointer to the DtD to search
3153 * @name: the notation name
3154 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003155 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003156 *
3157 * returns the xmlNotationPtr if found or NULL
3158 */
3159
3160xmlNotationPtr
3161xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3162 xmlNotationTablePtr table;
3163
3164 if (dtd == NULL) return(NULL);
3165 if (dtd->notations == NULL) return(NULL);
3166 table = (xmlNotationTablePtr) dtd->notations;
3167
3168 return(xmlHashLookup(table, name));
3169}
3170
Daniel Veillardf54cd532004-02-25 11:52:31 +00003171#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003172/**
3173 * xmlValidateNotationUse:
3174 * @ctxt: the validation context
3175 * @doc: the document
3176 * @notationName: the notation name to check
3177 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003178 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003179 * - [ VC: Notation Declared ]
3180 *
3181 * returns 1 if valid or 0 otherwise
3182 */
3183
3184int
3185xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3186 const xmlChar *notationName) {
3187 xmlNotationPtr notaDecl;
3188 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3189
3190 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3191 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3192 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3193
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003194 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003195 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3196 "NOTATION %s is not declared\n",
3197 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003198 return(0);
3199 }
3200 return(1);
3201}
Daniel Veillardf54cd532004-02-25 11:52:31 +00003202#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003203
3204/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003205 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003206 * @doc: the document
3207 * @name: the element name
3208 *
3209 * Search in the DtDs whether an element accept Mixed content (or ANY)
3210 * basically if it is supposed to accept text childs
3211 *
3212 * returns 0 if no, 1 if yes, and -1 if no element description is available
3213 */
3214
3215int
3216xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3217 xmlElementPtr elemDecl;
3218
3219 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3220
3221 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3222 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3223 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3224 if (elemDecl == NULL) return(-1);
3225 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003226 case XML_ELEMENT_TYPE_UNDEFINED:
3227 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003228 case XML_ELEMENT_TYPE_ELEMENT:
3229 return(0);
3230 case XML_ELEMENT_TYPE_EMPTY:
3231 /*
3232 * return 1 for EMPTY since we want VC error to pop up
3233 * on <empty> </empty> for example
3234 */
3235 case XML_ELEMENT_TYPE_ANY:
3236 case XML_ELEMENT_TYPE_MIXED:
3237 return(1);
3238 }
3239 return(1);
3240}
3241
Daniel Veillard4432df22003-09-28 18:58:27 +00003242#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003243/**
3244 * xmlValidateNameValue:
3245 * @value: an Name value
3246 *
3247 * Validate that the given value match Name production
3248 *
3249 * returns 1 if valid or 0 otherwise
3250 */
3251
Daniel Veillard9b731d72002-04-14 12:56:08 +00003252int
Owen Taylor3473f882001-02-23 17:55:21 +00003253xmlValidateNameValue(const xmlChar *value) {
3254 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003255 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003256
3257 if (value == NULL) return(0);
3258 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003259 val = xmlStringCurrentChar(NULL, cur, &len);
3260 cur += len;
3261 if (!IS_LETTER(val) && (val != '_') &&
3262 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003263 return(0);
3264 }
3265
Daniel Veillardd8224e02002-01-13 15:43:22 +00003266 val = xmlStringCurrentChar(NULL, cur, &len);
3267 cur += len;
3268 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3269 (val == '.') || (val == '-') ||
3270 (val == '_') || (val == ':') ||
3271 (IS_COMBINING(val)) ||
3272 (IS_EXTENDER(val))) {
3273 val = xmlStringCurrentChar(NULL, cur, &len);
3274 cur += len;
3275 }
Owen Taylor3473f882001-02-23 17:55:21 +00003276
Daniel Veillardd8224e02002-01-13 15:43:22 +00003277 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003278
3279 return(1);
3280}
3281
3282/**
3283 * xmlValidateNamesValue:
3284 * @value: an Names value
3285 *
3286 * Validate that the given value match Names production
3287 *
3288 * returns 1 if valid or 0 otherwise
3289 */
3290
Daniel Veillard9b731d72002-04-14 12:56:08 +00003291int
Owen Taylor3473f882001-02-23 17:55:21 +00003292xmlValidateNamesValue(const xmlChar *value) {
3293 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003294 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003295
3296 if (value == NULL) return(0);
3297 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003298 val = xmlStringCurrentChar(NULL, cur, &len);
3299 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003300
Daniel Veillardd8224e02002-01-13 15:43:22 +00003301 if (!IS_LETTER(val) && (val != '_') &&
3302 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003303 return(0);
3304 }
3305
Daniel Veillardd8224e02002-01-13 15:43:22 +00003306 val = xmlStringCurrentChar(NULL, cur, &len);
3307 cur += len;
3308 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3309 (val == '.') || (val == '-') ||
3310 (val == '_') || (val == ':') ||
3311 (IS_COMBINING(val)) ||
3312 (IS_EXTENDER(val))) {
3313 val = xmlStringCurrentChar(NULL, cur, &len);
3314 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003315 }
3316
Daniel Veillard807b4de2004-09-26 14:42:56 +00003317 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3318 while (val == 0x20) {
3319 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003320 val = xmlStringCurrentChar(NULL, cur, &len);
3321 cur += len;
3322 }
3323
3324 if (!IS_LETTER(val) && (val != '_') &&
3325 (val != ':')) {
3326 return(0);
3327 }
3328 val = xmlStringCurrentChar(NULL, cur, &len);
3329 cur += len;
3330
3331 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3332 (val == '.') || (val == '-') ||
3333 (val == '_') || (val == ':') ||
3334 (IS_COMBINING(val)) ||
3335 (IS_EXTENDER(val))) {
3336 val = xmlStringCurrentChar(NULL, cur, &len);
3337 cur += len;
3338 }
3339 }
3340
3341 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003342
3343 return(1);
3344}
3345
3346/**
3347 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003348 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003349 *
3350 * Validate that the given value match Nmtoken production
3351 *
3352 * [ VC: Name Token ]
3353 *
3354 * returns 1 if valid or 0 otherwise
3355 */
3356
Daniel Veillard9b731d72002-04-14 12:56:08 +00003357int
Owen Taylor3473f882001-02-23 17:55:21 +00003358xmlValidateNmtokenValue(const xmlChar *value) {
3359 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003360 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003361
3362 if (value == NULL) return(0);
3363 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003364 val = xmlStringCurrentChar(NULL, cur, &len);
3365 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003366
Daniel Veillardd8224e02002-01-13 15:43:22 +00003367 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3368 (val != '.') && (val != '-') &&
3369 (val != '_') && (val != ':') &&
3370 (!IS_COMBINING(val)) &&
3371 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003372 return(0);
3373
Daniel Veillardd8224e02002-01-13 15:43:22 +00003374 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3375 (val == '.') || (val == '-') ||
3376 (val == '_') || (val == ':') ||
3377 (IS_COMBINING(val)) ||
3378 (IS_EXTENDER(val))) {
3379 val = xmlStringCurrentChar(NULL, cur, &len);
3380 cur += len;
3381 }
Owen Taylor3473f882001-02-23 17:55:21 +00003382
Daniel Veillardd8224e02002-01-13 15:43:22 +00003383 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003384
3385 return(1);
3386}
3387
3388/**
3389 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003390 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003391 *
3392 * Validate that the given value match Nmtokens production
3393 *
3394 * [ VC: Name Token ]
3395 *
3396 * returns 1 if valid or 0 otherwise
3397 */
3398
Daniel Veillard9b731d72002-04-14 12:56:08 +00003399int
Owen Taylor3473f882001-02-23 17:55:21 +00003400xmlValidateNmtokensValue(const xmlChar *value) {
3401 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003402 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003403
3404 if (value == NULL) return(0);
3405 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003406 val = xmlStringCurrentChar(NULL, cur, &len);
3407 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003408
Daniel Veillardd8224e02002-01-13 15:43:22 +00003409 while (IS_BLANK(val)) {
3410 val = xmlStringCurrentChar(NULL, cur, &len);
3411 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003412 }
3413
Daniel Veillardd8224e02002-01-13 15:43:22 +00003414 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3415 (val != '.') && (val != '-') &&
3416 (val != '_') && (val != ':') &&
3417 (!IS_COMBINING(val)) &&
3418 (!IS_EXTENDER(val)))
3419 return(0);
3420
3421 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3422 (val == '.') || (val == '-') ||
3423 (val == '_') || (val == ':') ||
3424 (IS_COMBINING(val)) ||
3425 (IS_EXTENDER(val))) {
3426 val = xmlStringCurrentChar(NULL, cur, &len);
3427 cur += len;
3428 }
3429
Daniel Veillard807b4de2004-09-26 14:42:56 +00003430 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3431 while (val == 0x20) {
3432 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003433 val = xmlStringCurrentChar(NULL, cur, &len);
3434 cur += len;
3435 }
3436 if (val == 0) return(1);
3437
3438 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3439 (val != '.') && (val != '-') &&
3440 (val != '_') && (val != ':') &&
3441 (!IS_COMBINING(val)) &&
3442 (!IS_EXTENDER(val)))
3443 return(0);
3444
3445 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3446 (val == '.') || (val == '-') ||
3447 (val == '_') || (val == ':') ||
3448 (IS_COMBINING(val)) ||
3449 (IS_EXTENDER(val))) {
3450 val = xmlStringCurrentChar(NULL, cur, &len);
3451 cur += len;
3452 }
3453 }
3454
3455 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003456
3457 return(1);
3458}
3459
3460/**
3461 * xmlValidateNotationDecl:
3462 * @ctxt: the validation context
3463 * @doc: a document instance
3464 * @nota: a notation definition
3465 *
3466 * Try to validate a single notation definition
3467 * basically it does the following checks as described by the
3468 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003469 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003470 * But this function get called anyway ...
3471 *
3472 * returns 1 if valid or 0 otherwise
3473 */
3474
3475int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003476xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3477 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003478 int ret = 1;
3479
3480 return(ret);
3481}
3482
3483/**
3484 * xmlValidateAttributeValue:
3485 * @type: an attribute type
3486 * @value: an attribute value
3487 *
3488 * Validate that the given attribute value match the proper production
3489 *
3490 * [ VC: ID ]
3491 * Values of type ID must match the Name production....
3492 *
3493 * [ VC: IDREF ]
3494 * Values of type IDREF must match the Name production, and values
3495 * of type IDREFS must match Names ...
3496 *
3497 * [ VC: Entity Name ]
3498 * Values of type ENTITY must match the Name production, values
3499 * of type ENTITIES must match Names ...
3500 *
3501 * [ VC: Name Token ]
3502 * Values of type NMTOKEN must match the Nmtoken production; values
3503 * of type NMTOKENS must match Nmtokens.
3504 *
3505 * returns 1 if valid or 0 otherwise
3506 */
3507
3508int
3509xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3510 switch (type) {
3511 case XML_ATTRIBUTE_ENTITIES:
3512 case XML_ATTRIBUTE_IDREFS:
3513 return(xmlValidateNamesValue(value));
3514 case XML_ATTRIBUTE_ENTITY:
3515 case XML_ATTRIBUTE_IDREF:
3516 case XML_ATTRIBUTE_ID:
3517 case XML_ATTRIBUTE_NOTATION:
3518 return(xmlValidateNameValue(value));
3519 case XML_ATTRIBUTE_NMTOKENS:
3520 case XML_ATTRIBUTE_ENUMERATION:
3521 return(xmlValidateNmtokensValue(value));
3522 case XML_ATTRIBUTE_NMTOKEN:
3523 return(xmlValidateNmtokenValue(value));
3524 case XML_ATTRIBUTE_CDATA:
3525 break;
3526 }
3527 return(1);
3528}
3529
3530/**
3531 * xmlValidateAttributeValue2:
3532 * @ctxt: the validation context
3533 * @doc: the document
3534 * @name: the attribute name (used for error reporting only)
3535 * @type: the attribute type
3536 * @value: the attribute value
3537 *
3538 * Validate that the given attribute value match a given type.
3539 * This typically cannot be done before having finished parsing
3540 * the subsets.
3541 *
3542 * [ VC: IDREF ]
3543 * Values of type IDREF must match one of the declared IDs
3544 * Values of type IDREFS must match a sequence of the declared IDs
3545 * each Name must match the value of an ID attribute on some element
3546 * in the XML document; i.e. IDREF values must match the value of
3547 * some ID attribute
3548 *
3549 * [ VC: Entity Name ]
3550 * Values of type ENTITY must match one declared entity
3551 * Values of type ENTITIES must match a sequence of declared entities
3552 *
3553 * [ VC: Notation Attributes ]
3554 * all notation names in the declaration must be declared.
3555 *
3556 * returns 1 if valid or 0 otherwise
3557 */
3558
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003559static int
Owen Taylor3473f882001-02-23 17:55:21 +00003560xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3561 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3562 int ret = 1;
3563 switch (type) {
3564 case XML_ATTRIBUTE_IDREFS:
3565 case XML_ATTRIBUTE_IDREF:
3566 case XML_ATTRIBUTE_ID:
3567 case XML_ATTRIBUTE_NMTOKENS:
3568 case XML_ATTRIBUTE_ENUMERATION:
3569 case XML_ATTRIBUTE_NMTOKEN:
3570 case XML_ATTRIBUTE_CDATA:
3571 break;
3572 case XML_ATTRIBUTE_ENTITY: {
3573 xmlEntityPtr ent;
3574
3575 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003576 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003577 if ((ent == NULL) && (doc->standalone == 1)) {
3578 doc->standalone = 0;
3579 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003580 }
Owen Taylor3473f882001-02-23 17:55:21 +00003581 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003582 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3583 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003584 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003585 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003586 ret = 0;
3587 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003588 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3589 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003590 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003591 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003592 ret = 0;
3593 }
3594 break;
3595 }
3596 case XML_ATTRIBUTE_ENTITIES: {
3597 xmlChar *dup, *nam = NULL, *cur, save;
3598 xmlEntityPtr ent;
3599
3600 dup = xmlStrdup(value);
3601 if (dup == NULL)
3602 return(0);
3603 cur = dup;
3604 while (*cur != 0) {
3605 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003606 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003607 save = *cur;
3608 *cur = 0;
3609 ent = xmlGetDocEntity(doc, nam);
3610 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003611 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3612 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003613 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003614 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003615 ret = 0;
3616 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003617 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3618 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003619 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003620 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003621 ret = 0;
3622 }
3623 if (save == 0)
3624 break;
3625 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003626 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003627 }
3628 xmlFree(dup);
3629 break;
3630 }
3631 case XML_ATTRIBUTE_NOTATION: {
3632 xmlNotationPtr nota;
3633
3634 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3635 if ((nota == NULL) && (doc->extSubset != NULL))
3636 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3637
3638 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003639 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3640 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003641 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003642 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003643 ret = 0;
3644 }
3645 break;
3646 }
3647 }
3648 return(ret);
3649}
3650
3651/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003652 * xmlValidCtxtNormalizeAttributeValue:
3653 * @ctxt: the validation context
3654 * @doc: the document
3655 * @elem: the parent
3656 * @name: the attribute name
3657 * @value: the attribute value
3658 * @ctxt: the validation context or NULL
3659 *
3660 * Does the validation related extra step of the normalization of attribute
3661 * values:
3662 *
3663 * If the declared value is not CDATA, then the XML processor must further
3664 * process the normalized attribute value by discarding any leading and
3665 * trailing space (#x20) characters, and by replacing sequences of space
3666 * (#x20) characters by single space (#x20) character.
3667 *
3668 * Also check VC: Standalone Document Declaration in P32, and update
3669 * ctxt->valid accordingly
3670 *
3671 * returns a new normalized string if normalization is needed, NULL otherwise
3672 * the caller must free the returned value.
3673 */
3674
3675xmlChar *
3676xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3677 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3678 xmlChar *ret, *dst;
3679 const xmlChar *src;
3680 xmlAttributePtr attrDecl = NULL;
3681 int extsubset = 0;
3682
3683 if (doc == NULL) return(NULL);
3684 if (elem == NULL) return(NULL);
3685 if (name == NULL) return(NULL);
3686 if (value == NULL) return(NULL);
3687
3688 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003689 xmlChar fn[50];
3690 xmlChar *fullname;
3691
3692 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3693 if (fullname == NULL)
3694 return(0);
3695 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003696 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003697 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003698 if (attrDecl != NULL)
3699 extsubset = 1;
3700 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003701 if ((fullname != fn) && (fullname != elem->name))
3702 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003703 }
3704 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3705 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3706 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3707 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3708 if (attrDecl != NULL)
3709 extsubset = 1;
3710 }
3711
3712 if (attrDecl == NULL)
3713 return(NULL);
3714 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3715 return(NULL);
3716
3717 ret = xmlStrdup(value);
3718 if (ret == NULL)
3719 return(NULL);
3720 src = value;
3721 dst = ret;
3722 while (*src == 0x20) src++;
3723 while (*src != 0) {
3724 if (*src == 0x20) {
3725 while (*src == 0x20) src++;
3726 if (*src != 0)
3727 *dst++ = 0x20;
3728 } else {
3729 *dst++ = *src++;
3730 }
3731 }
3732 *dst = 0;
3733 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003734 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003735"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003736 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003737 ctxt->valid = 0;
3738 }
3739 return(ret);
3740}
3741
3742/**
Owen Taylor3473f882001-02-23 17:55:21 +00003743 * xmlValidNormalizeAttributeValue:
3744 * @doc: the document
3745 * @elem: the parent
3746 * @name: the attribute name
3747 * @value: the attribute value
3748 *
3749 * Does the validation related extra step of the normalization of attribute
3750 * values:
3751 *
3752 * If the declared value is not CDATA, then the XML processor must further
3753 * process the normalized attribute value by discarding any leading and
3754 * trailing space (#x20) characters, and by replacing sequences of space
3755 * (#x20) characters by single space (#x20) character.
3756 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003757 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003758 * the caller must free the returned value.
3759 */
3760
3761xmlChar *
3762xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3763 const xmlChar *name, const xmlChar *value) {
3764 xmlChar *ret, *dst;
3765 const xmlChar *src;
3766 xmlAttributePtr attrDecl = NULL;
3767
3768 if (doc == NULL) return(NULL);
3769 if (elem == NULL) return(NULL);
3770 if (name == NULL) return(NULL);
3771 if (value == NULL) return(NULL);
3772
3773 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003774 xmlChar fn[50];
3775 xmlChar *fullname;
3776
3777 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3778 if (fullname == NULL)
3779 return(0);
3780 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003781 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003782 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3783 if ((fullname != fn) && (fullname != elem->name))
3784 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003785 }
3786 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3787 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3788 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3789
3790 if (attrDecl == NULL)
3791 return(NULL);
3792 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3793 return(NULL);
3794
3795 ret = xmlStrdup(value);
3796 if (ret == NULL)
3797 return(NULL);
3798 src = value;
3799 dst = ret;
3800 while (*src == 0x20) src++;
3801 while (*src != 0) {
3802 if (*src == 0x20) {
3803 while (*src == 0x20) src++;
3804 if (*src != 0)
3805 *dst++ = 0x20;
3806 } else {
3807 *dst++ = *src++;
3808 }
3809 }
3810 *dst = 0;
3811 return(ret);
3812}
3813
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003814static void
Owen Taylor3473f882001-02-23 17:55:21 +00003815xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003816 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003817 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3818}
3819
3820/**
3821 * xmlValidateAttributeDecl:
3822 * @ctxt: the validation context
3823 * @doc: a document instance
3824 * @attr: an attribute definition
3825 *
3826 * Try to validate a single attribute definition
3827 * basically it does the following checks as described by the
3828 * XML-1.0 recommendation:
3829 * - [ VC: Attribute Default Legal ]
3830 * - [ VC: Enumeration ]
3831 * - [ VC: ID Attribute Default ]
3832 *
3833 * The ID/IDREF uniqueness and matching are done separately
3834 *
3835 * returns 1 if valid or 0 otherwise
3836 */
3837
3838int
3839xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3840 xmlAttributePtr attr) {
3841 int ret = 1;
3842 int val;
3843 CHECK_DTD;
3844 if(attr == NULL) return(1);
3845
3846 /* Attribute Default Legal */
3847 /* Enumeration */
3848 if (attr->defaultValue != NULL) {
3849 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3850 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003851 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003852 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003853 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003854 }
3855 ret &= val;
3856 }
3857
3858 /* ID Attribute Default */
3859 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3860 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3861 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003862 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003863 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003864 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003865 ret = 0;
3866 }
3867
3868 /* One ID per Element Type */
3869 if (attr->atype == XML_ATTRIBUTE_ID) {
3870 int nbId;
3871
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003872 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00003873 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3874 attr->elem);
3875 if (elem != NULL) {
3876 nbId = xmlScanIDAttributeDecl(NULL, elem);
3877 } else {
3878 xmlAttributeTablePtr table;
3879
3880 /*
3881 * The attribute may be declared in the internal subset and the
3882 * element in the external subset.
3883 */
3884 nbId = 0;
3885 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3886 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3887 xmlValidateAttributeIdCallback, &nbId);
3888 }
3889 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003890
3891 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003892 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3893 attr->elem, nbId, attr->name);
3894 } else if (doc->extSubset != NULL) {
3895 int extId = 0;
3896 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3897 if (elem != NULL) {
3898 extId = xmlScanIDAttributeDecl(NULL, elem);
3899 }
3900 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003901 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003902 "Element %s has %d ID attribute defined in the external subset : %s\n",
3903 attr->elem, extId, attr->name);
3904 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003905 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003906"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003907 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003908 }
3909 }
3910 }
3911
3912 /* Validity Constraint: Enumeration */
3913 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3914 xmlEnumerationPtr tree = attr->tree;
3915 while (tree != NULL) {
3916 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3917 tree = tree->next;
3918 }
3919 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003920 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003921"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003922 attr->defaultValue, attr->name, attr->elem);
3923 ret = 0;
3924 }
3925 }
3926
3927 return(ret);
3928}
3929
3930/**
3931 * xmlValidateElementDecl:
3932 * @ctxt: the validation context
3933 * @doc: a document instance
3934 * @elem: an element definition
3935 *
3936 * Try to validate a single element definition
3937 * basically it does the following checks as described by the
3938 * XML-1.0 recommendation:
3939 * - [ VC: One ID per Element Type ]
3940 * - [ VC: No Duplicate Types ]
3941 * - [ VC: Unique Element Type Declaration ]
3942 *
3943 * returns 1 if valid or 0 otherwise
3944 */
3945
3946int
3947xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3948 xmlElementPtr elem) {
3949 int ret = 1;
3950 xmlElementPtr tst;
3951
3952 CHECK_DTD;
3953
3954 if (elem == NULL) return(1);
3955
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003956#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00003957#ifdef LIBXML_REGEXP_ENABLED
3958 /* Build the regexp associated to the content model */
3959 ret = xmlValidBuildContentModel(ctxt, elem);
3960#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003961#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00003962
Owen Taylor3473f882001-02-23 17:55:21 +00003963 /* No Duplicate Types */
3964 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3965 xmlElementContentPtr cur, next;
3966 const xmlChar *name;
3967
3968 cur = elem->content;
3969 while (cur != NULL) {
3970 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3971 if (cur->c1 == NULL) break;
3972 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3973 name = cur->c1->name;
3974 next = cur->c2;
3975 while (next != NULL) {
3976 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00003977 if ((xmlStrEqual(next->name, name)) &&
3978 (xmlStrEqual(next->prefix, cur->prefix))) {
3979 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003980 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00003981 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003982 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003983 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003984 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003985 "Definition of %s has duplicate references of %s:%s\n",
3986 elem->name, cur->prefix, name);
3987 }
Owen Taylor3473f882001-02-23 17:55:21 +00003988 ret = 0;
3989 }
3990 break;
3991 }
3992 if (next->c1 == NULL) break;
3993 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00003994 if ((xmlStrEqual(next->c1->name, name)) &&
3995 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
3996 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003997 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003998 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003999 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004000 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004001 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004002 "Definition of %s has duplicate references to %s:%s\n",
4003 elem->name, cur->prefix, name);
4004 }
Owen Taylor3473f882001-02-23 17:55:21 +00004005 ret = 0;
4006 }
4007 next = next->c2;
4008 }
4009 }
4010 cur = cur->c2;
4011 }
4012 }
4013
4014 /* VC: Unique Element Type Declaration */
4015 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004016 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004017 ((tst->prefix == elem->prefix) ||
4018 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004019 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004020 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4021 "Redefinition of element %s\n",
4022 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004023 ret = 0;
4024 }
4025 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004026 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004027 ((tst->prefix == elem->prefix) ||
4028 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004029 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004030 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4031 "Redefinition of element %s\n",
4032 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004033 ret = 0;
4034 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004035 /* One ID per Element Type
4036 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004037 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4038 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004039 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004040 return(ret);
4041}
4042
4043/**
4044 * xmlValidateOneAttribute:
4045 * @ctxt: the validation context
4046 * @doc: a document instance
4047 * @elem: an element instance
4048 * @attr: an attribute instance
4049 * @value: the attribute value (without entities processing)
4050 *
4051 * Try to validate a single attribute for an element
4052 * basically it does the following checks as described by the
4053 * XML-1.0 recommendation:
4054 * - [ VC: Attribute Value Type ]
4055 * - [ VC: Fixed Attribute Default ]
4056 * - [ VC: Entity Name ]
4057 * - [ VC: Name Token ]
4058 * - [ VC: ID ]
4059 * - [ VC: IDREF ]
4060 * - [ VC: Entity Name ]
4061 * - [ VC: Notation Attributes ]
4062 *
4063 * The ID/IDREF uniqueness and matching are done separately
4064 *
4065 * returns 1 if valid or 0 otherwise
4066 */
4067
4068int
4069xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004070 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4071{
Owen Taylor3473f882001-02-23 17:55:21 +00004072 xmlAttributePtr attrDecl = NULL;
4073 int val;
4074 int ret = 1;
4075
4076 CHECK_DTD;
4077 if ((elem == NULL) || (elem->name == NULL)) return(0);
4078 if ((attr == NULL) || (attr->name == NULL)) return(0);
4079
4080 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004081 xmlChar fn[50];
4082 xmlChar *fullname;
4083
4084 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4085 if (fullname == NULL)
4086 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004087 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004088 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004089 attr->name, attr->ns->prefix);
4090 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004091 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004092 attr->name, attr->ns->prefix);
4093 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004094 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004095 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4096 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004097 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004098 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004099 if ((fullname != fn) && (fullname != elem->name))
4100 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004101 }
4102 if (attrDecl == NULL) {
4103 if (attr->ns != NULL) {
4104 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4105 attr->name, attr->ns->prefix);
4106 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4107 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4108 attr->name, attr->ns->prefix);
4109 } else {
4110 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4111 elem->name, attr->name);
4112 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4113 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4114 elem->name, attr->name);
4115 }
4116 }
4117
4118
4119 /* Validity Constraint: Attribute Value Type */
4120 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004121 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004122 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004123 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004124 return(0);
4125 }
4126 attr->atype = attrDecl->atype;
4127
4128 val = xmlValidateAttributeValue(attrDecl->atype, value);
4129 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004130 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004131 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004132 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004133 ret = 0;
4134 }
4135
4136 /* Validity constraint: Fixed Attribute Default */
4137 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4138 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004139 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004140 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004141 attr->name, elem->name, attrDecl->defaultValue);
4142 ret = 0;
4143 }
4144 }
4145
4146 /* Validity Constraint: ID uniqueness */
4147 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4148 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4149 ret = 0;
4150 }
4151
4152 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4153 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4154 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4155 ret = 0;
4156 }
4157
4158 /* Validity Constraint: Notation Attributes */
4159 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4160 xmlEnumerationPtr tree = attrDecl->tree;
4161 xmlNotationPtr nota;
4162
4163 /* First check that the given NOTATION was declared */
4164 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4165 if (nota == NULL)
4166 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4167
4168 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004169 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004170 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004171 value, attr->name, elem->name);
4172 ret = 0;
4173 }
4174
4175 /* Second, verify that it's among the list */
4176 while (tree != NULL) {
4177 if (xmlStrEqual(tree->name, value)) break;
4178 tree = tree->next;
4179 }
4180 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004181 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004182"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004183 value, attr->name, elem->name);
4184 ret = 0;
4185 }
4186 }
4187
4188 /* Validity Constraint: Enumeration */
4189 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4190 xmlEnumerationPtr tree = attrDecl->tree;
4191 while (tree != NULL) {
4192 if (xmlStrEqual(tree->name, value)) break;
4193 tree = tree->next;
4194 }
4195 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004196 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004197 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004198 value, attr->name, elem->name);
4199 ret = 0;
4200 }
4201 }
4202
4203 /* Fixed Attribute Default */
4204 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4205 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004206 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004207 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004208 attr->name, elem->name, attrDecl->defaultValue);
4209 ret = 0;
4210 }
4211
4212 /* Extra check for the attribute value */
4213 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4214 attrDecl->atype, value);
4215
4216 return(ret);
4217}
4218
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004219/**
4220 * xmlValidateOneNamespace:
4221 * @ctxt: the validation context
4222 * @doc: a document instance
4223 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004224 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004225 * @ns: an namespace declaration instance
4226 * @value: the attribute value (without entities processing)
4227 *
4228 * Try to validate a single namespace declaration for an element
4229 * basically it does the following checks as described by the
4230 * XML-1.0 recommendation:
4231 * - [ VC: Attribute Value Type ]
4232 * - [ VC: Fixed Attribute Default ]
4233 * - [ VC: Entity Name ]
4234 * - [ VC: Name Token ]
4235 * - [ VC: ID ]
4236 * - [ VC: IDREF ]
4237 * - [ VC: Entity Name ]
4238 * - [ VC: Notation Attributes ]
4239 *
4240 * The ID/IDREF uniqueness and matching are done separately
4241 *
4242 * returns 1 if valid or 0 otherwise
4243 */
4244
4245int
4246xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4247xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4248 /* xmlElementPtr elemDecl; */
4249 xmlAttributePtr attrDecl = NULL;
4250 int val;
4251 int ret = 1;
4252
4253 CHECK_DTD;
4254 if ((elem == NULL) || (elem->name == NULL)) return(0);
4255 if ((ns == NULL) || (ns->href == NULL)) return(0);
4256
4257 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004258 xmlChar fn[50];
4259 xmlChar *fullname;
4260
4261 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4262 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004263 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004264 return(0);
4265 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004266 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004267 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004268 ns->prefix, BAD_CAST "xmlns");
4269 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004270 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004271 ns->prefix, BAD_CAST "xmlns");
4272 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004273 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004274 BAD_CAST "xmlns");
4275 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004276 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004277 BAD_CAST "xmlns");
4278 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004279 if ((fullname != fn) && (fullname != elem->name))
4280 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004281 }
4282 if (attrDecl == NULL) {
4283 if (ns->prefix != NULL) {
4284 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4285 ns->prefix, BAD_CAST "xmlns");
4286 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4287 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4288 ns->prefix, BAD_CAST "xmlns");
4289 } else {
4290 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4291 elem->name, BAD_CAST "xmlns");
4292 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4293 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4294 elem->name, BAD_CAST "xmlns");
4295 }
4296 }
4297
4298
4299 /* Validity Constraint: Attribute Value Type */
4300 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004301 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004302 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004303 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004304 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004305 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004306 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004307 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004308 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004309 }
4310 return(0);
4311 }
4312
4313 val = xmlValidateAttributeValue(attrDecl->atype, value);
4314 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004315 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004316 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004317 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004318 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004319 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004320 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004321 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004322 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004323 }
4324 ret = 0;
4325 }
4326
4327 /* Validity constraint: Fixed Attribute Default */
4328 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4329 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004330 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004331 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004332 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4333 ns->prefix, elem->name, attrDecl->defaultValue);
4334 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004335 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004336 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004337 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004338 }
4339 ret = 0;
4340 }
4341 }
4342
4343 /* Validity Constraint: ID uniqueness */
4344 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4345 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4346 ret = 0;
4347 }
4348
4349 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4350 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4351 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4352 ret = 0;
4353 }
4354
4355 /* Validity Constraint: Notation Attributes */
4356 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4357 xmlEnumerationPtr tree = attrDecl->tree;
4358 xmlNotationPtr nota;
4359
4360 /* First check that the given NOTATION was declared */
4361 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4362 if (nota == NULL)
4363 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4364
4365 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004366 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004367 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004368 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4369 value, ns->prefix, elem->name);
4370 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004371 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004372 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004373 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004374 }
4375 ret = 0;
4376 }
4377
4378 /* Second, verify that it's among the list */
4379 while (tree != NULL) {
4380 if (xmlStrEqual(tree->name, value)) break;
4381 tree = tree->next;
4382 }
4383 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004384 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004385 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004386"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4387 value, ns->prefix, elem->name);
4388 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004389 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004390"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004391 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004392 }
4393 ret = 0;
4394 }
4395 }
4396
4397 /* Validity Constraint: Enumeration */
4398 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4399 xmlEnumerationPtr tree = attrDecl->tree;
4400 while (tree != NULL) {
4401 if (xmlStrEqual(tree->name, value)) break;
4402 tree = tree->next;
4403 }
4404 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004405 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004406 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004407"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4408 value, ns->prefix, elem->name);
4409 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004410 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004411"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004412 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004413 }
4414 ret = 0;
4415 }
4416 }
4417
4418 /* Fixed Attribute Default */
4419 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4420 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004421 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004422 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004423 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4424 ns->prefix, elem->name, attrDecl->defaultValue);
4425 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004426 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004427 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004428 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004429 }
4430 ret = 0;
4431 }
4432
4433 /* Extra check for the attribute value */
4434 if (ns->prefix != NULL) {
4435 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4436 attrDecl->atype, value);
4437 } else {
4438 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4439 attrDecl->atype, value);
4440 }
4441
4442 return(ret);
4443}
4444
Daniel Veillard118aed72002-09-24 14:13:13 +00004445#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004446/**
4447 * xmlValidateSkipIgnorable:
4448 * @ctxt: the validation context
4449 * @child: the child list
4450 *
4451 * Skip ignorable elements w.r.t. the validation process
4452 *
4453 * returns the first element to consider for validation of the content model
4454 */
4455
4456static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004457xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004458 while (child != NULL) {
4459 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004460 /* These things are ignored (skipped) during validation. */
4461 case XML_PI_NODE:
4462 case XML_COMMENT_NODE:
4463 case XML_XINCLUDE_START:
4464 case XML_XINCLUDE_END:
4465 child = child->next;
4466 break;
4467 case XML_TEXT_NODE:
4468 if (xmlIsBlankNode(child))
4469 child = child->next;
4470 else
4471 return(child);
4472 break;
4473 /* keep current node */
4474 default:
4475 return(child);
4476 }
4477 }
4478 return(child);
4479}
4480
4481/**
4482 * xmlValidateElementType:
4483 * @ctxt: the validation context
4484 *
4485 * Try to validate the content model of an element internal function
4486 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004487 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4488 * reference is found and -3 if the validation succeeded but
4489 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004490 */
4491
4492static int
4493xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004494 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004495 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004496
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004497 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004498 if ((NODE == NULL) && (CONT == NULL))
4499 return(1);
4500 if ((NODE == NULL) &&
4501 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4502 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4503 return(1);
4504 }
4505 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004506 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004507 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004508
4509 /*
4510 * We arrive here when more states need to be examined
4511 */
4512cont:
4513
4514 /*
4515 * We just recovered from a rollback generated by a possible
4516 * epsilon transition, go directly to the analysis phase
4517 */
4518 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004519 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004520 DEBUG_VALID_STATE(NODE, CONT)
4521 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004522 goto analyze;
4523 }
4524
4525 DEBUG_VALID_STATE(NODE, CONT)
4526 /*
4527 * we may have to save a backup state here. This is the equivalent
4528 * of handling epsilon transition in NFAs.
4529 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004530 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004531 ((CONT->parent == NULL) ||
4532 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004533 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004534 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004535 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004536 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004537 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4538 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004539 }
4540
4541
4542 /*
4543 * Check first if the content matches
4544 */
4545 switch (CONT->type) {
4546 case XML_ELEMENT_CONTENT_PCDATA:
4547 if (NODE == NULL) {
4548 DEBUG_VALID_MSG("pcdata failed no node");
4549 ret = 0;
4550 break;
4551 }
4552 if (NODE->type == XML_TEXT_NODE) {
4553 DEBUG_VALID_MSG("pcdata found, skip to next");
4554 /*
4555 * go to next element in the content model
4556 * skipping ignorable elems
4557 */
4558 do {
4559 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004560 NODE = xmlValidateSkipIgnorable(NODE);
4561 if ((NODE != NULL) &&
4562 (NODE->type == XML_ENTITY_REF_NODE))
4563 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004564 } while ((NODE != NULL) &&
4565 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004566 (NODE->type != XML_TEXT_NODE) &&
4567 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004568 ret = 1;
4569 break;
4570 } else {
4571 DEBUG_VALID_MSG("pcdata failed");
4572 ret = 0;
4573 break;
4574 }
4575 break;
4576 case XML_ELEMENT_CONTENT_ELEMENT:
4577 if (NODE == NULL) {
4578 DEBUG_VALID_MSG("element failed no node");
4579 ret = 0;
4580 break;
4581 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004582 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4583 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004584 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004585 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4586 ret = (CONT->prefix == NULL);
4587 } else if (CONT->prefix == NULL) {
4588 ret = 0;
4589 } else {
4590 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4591 }
4592 }
4593 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004594 DEBUG_VALID_MSG("element found, skip to next");
4595 /*
4596 * go to next element in the content model
4597 * skipping ignorable elems
4598 */
4599 do {
4600 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004601 NODE = xmlValidateSkipIgnorable(NODE);
4602 if ((NODE != NULL) &&
4603 (NODE->type == XML_ENTITY_REF_NODE))
4604 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004605 } while ((NODE != NULL) &&
4606 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004607 (NODE->type != XML_TEXT_NODE) &&
4608 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004609 } else {
4610 DEBUG_VALID_MSG("element failed");
4611 ret = 0;
4612 break;
4613 }
4614 break;
4615 case XML_ELEMENT_CONTENT_OR:
4616 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004617 * Small optimization.
4618 */
4619 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4620 if ((NODE == NULL) ||
4621 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4622 DEPTH++;
4623 CONT = CONT->c2;
4624 goto cont;
4625 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004626 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4627 ret = (CONT->c1->prefix == NULL);
4628 } else if (CONT->c1->prefix == NULL) {
4629 ret = 0;
4630 } else {
4631 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4632 }
4633 if (ret == 0) {
4634 DEPTH++;
4635 CONT = CONT->c2;
4636 goto cont;
4637 }
Daniel Veillard85349052001-04-20 13:48:21 +00004638 }
4639
4640 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004641 * save the second branch 'or' branch
4642 */
4643 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004644 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4645 OCCURS, ROLLBACK_OR) < 0)
4646 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004647 DEPTH++;
4648 CONT = CONT->c1;
4649 goto cont;
4650 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004651 /*
4652 * Small optimization.
4653 */
4654 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4655 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4656 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4657 if ((NODE == NULL) ||
4658 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4659 DEPTH++;
4660 CONT = CONT->c2;
4661 goto cont;
4662 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004663 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4664 ret = (CONT->c1->prefix == NULL);
4665 } else if (CONT->c1->prefix == NULL) {
4666 ret = 0;
4667 } else {
4668 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4669 }
4670 if (ret == 0) {
4671 DEPTH++;
4672 CONT = CONT->c2;
4673 goto cont;
4674 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004675 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004676 DEPTH++;
4677 CONT = CONT->c1;
4678 goto cont;
4679 }
4680
4681 /*
4682 * At this point handle going up in the tree
4683 */
4684 if (ret == -1) {
4685 DEBUG_VALID_MSG("error found returning");
4686 return(ret);
4687 }
4688analyze:
4689 while (CONT != NULL) {
4690 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004691 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004692 * this level.
4693 */
4694 if (ret == 0) {
4695 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004696 xmlNodePtr cur;
4697
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004698 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004699 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004700 DEBUG_VALID_MSG("Once branch failed, rollback");
4701 if (vstateVPop(ctxt) < 0 ) {
4702 DEBUG_VALID_MSG("exhaustion, failed");
4703 return(0);
4704 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004705 if (cur != ctxt->vstate->node)
4706 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004707 goto cont;
4708 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004709 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004710 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004711 DEBUG_VALID_MSG("Plus branch failed, rollback");
4712 if (vstateVPop(ctxt) < 0 ) {
4713 DEBUG_VALID_MSG("exhaustion, failed");
4714 return(0);
4715 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004716 if (cur != ctxt->vstate->node)
4717 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004718 goto cont;
4719 }
4720 DEBUG_VALID_MSG("Plus branch found");
4721 ret = 1;
4722 break;
4723 case XML_ELEMENT_CONTENT_MULT:
4724#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004725 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004726 DEBUG_VALID_MSG("Mult branch failed");
4727 } else {
4728 DEBUG_VALID_MSG("Mult branch found");
4729 }
4730#endif
4731 ret = 1;
4732 break;
4733 case XML_ELEMENT_CONTENT_OPT:
4734 DEBUG_VALID_MSG("Option branch failed");
4735 ret = 1;
4736 break;
4737 }
4738 } else {
4739 switch (CONT->ocur) {
4740 case XML_ELEMENT_CONTENT_OPT:
4741 DEBUG_VALID_MSG("Option branch succeeded");
4742 ret = 1;
4743 break;
4744 case XML_ELEMENT_CONTENT_ONCE:
4745 DEBUG_VALID_MSG("Once branch succeeded");
4746 ret = 1;
4747 break;
4748 case XML_ELEMENT_CONTENT_PLUS:
4749 if (STATE == ROLLBACK_PARENT) {
4750 DEBUG_VALID_MSG("Plus branch rollback");
4751 ret = 1;
4752 break;
4753 }
4754 if (NODE == NULL) {
4755 DEBUG_VALID_MSG("Plus branch exhausted");
4756 ret = 1;
4757 break;
4758 }
4759 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004760 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004761 goto cont;
4762 case XML_ELEMENT_CONTENT_MULT:
4763 if (STATE == ROLLBACK_PARENT) {
4764 DEBUG_VALID_MSG("Mult branch rollback");
4765 ret = 1;
4766 break;
4767 }
4768 if (NODE == NULL) {
4769 DEBUG_VALID_MSG("Mult branch exhausted");
4770 ret = 1;
4771 break;
4772 }
4773 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004774 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004775 goto cont;
4776 }
4777 }
4778 STATE = 0;
4779
4780 /*
4781 * Then act accordingly at the parent level
4782 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004783 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004784 if (CONT->parent == NULL)
4785 break;
4786
4787 switch (CONT->parent->type) {
4788 case XML_ELEMENT_CONTENT_PCDATA:
4789 DEBUG_VALID_MSG("Error: parent pcdata");
4790 return(-1);
4791 case XML_ELEMENT_CONTENT_ELEMENT:
4792 DEBUG_VALID_MSG("Error: parent element");
4793 return(-1);
4794 case XML_ELEMENT_CONTENT_OR:
4795 if (ret == 1) {
4796 DEBUG_VALID_MSG("Or succeeded");
4797 CONT = CONT->parent;
4798 DEPTH--;
4799 } else {
4800 DEBUG_VALID_MSG("Or failed");
4801 CONT = CONT->parent;
4802 DEPTH--;
4803 }
4804 break;
4805 case XML_ELEMENT_CONTENT_SEQ:
4806 if (ret == 0) {
4807 DEBUG_VALID_MSG("Sequence failed");
4808 CONT = CONT->parent;
4809 DEPTH--;
4810 } else if (CONT == CONT->parent->c1) {
4811 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4812 CONT = CONT->parent->c2;
4813 goto cont;
4814 } else {
4815 DEBUG_VALID_MSG("Sequence succeeded");
4816 CONT = CONT->parent;
4817 DEPTH--;
4818 }
4819 }
4820 }
4821 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004822 xmlNodePtr cur;
4823
4824 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004825 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4826 if (vstateVPop(ctxt) < 0 ) {
4827 DEBUG_VALID_MSG("exhaustion, failed");
4828 return(0);
4829 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004830 if (cur != ctxt->vstate->node)
4831 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004832 goto cont;
4833 }
4834 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004835 xmlNodePtr cur;
4836
4837 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004838 DEBUG_VALID_MSG("Failure, rollback");
4839 if (vstateVPop(ctxt) < 0 ) {
4840 DEBUG_VALID_MSG("exhaustion, failed");
4841 return(0);
4842 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004843 if (cur != ctxt->vstate->node)
4844 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004845 goto cont;
4846 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004847 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004848}
Daniel Veillard23e73572002-09-19 19:56:43 +00004849#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004850
4851/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00004852 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004853 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00004854 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004855 * @content: An element
4856 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4857 *
4858 * This will dump the list of elements to the buffer
4859 * Intended just for the debug routine
4860 */
4861static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00004862xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004863 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00004864 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004865
4866 if (node == NULL) return;
4867 if (glob) strcat(buf, "(");
4868 cur = node;
4869 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004870 len = strlen(buf);
4871 if (size - len < 50) {
4872 if ((size - len > 4) && (buf[len - 1] != '.'))
4873 strcat(buf, " ...");
4874 return;
4875 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004876 switch (cur->type) {
4877 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004878 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004879 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004880 if ((size - len > 4) && (buf[len - 1] != '.'))
4881 strcat(buf, " ...");
4882 return;
4883 }
4884 strcat(buf, (char *) cur->ns->prefix);
4885 strcat(buf, ":");
4886 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004887 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004888 if ((size - len > 4) && (buf[len - 1] != '.'))
4889 strcat(buf, " ...");
4890 return;
4891 }
4892 strcat(buf, (char *) cur->name);
4893 if (cur->next != NULL)
4894 strcat(buf, " ");
4895 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004896 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004897 if (xmlIsBlankNode(cur))
4898 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004899 case XML_CDATA_SECTION_NODE:
4900 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004901 strcat(buf, "CDATA");
4902 if (cur->next != NULL)
4903 strcat(buf, " ");
4904 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004905 case XML_ATTRIBUTE_NODE:
4906 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004907#ifdef LIBXML_DOCB_ENABLED
4908 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004909#endif
4910 case XML_HTML_DOCUMENT_NODE:
4911 case XML_DOCUMENT_TYPE_NODE:
4912 case XML_DOCUMENT_FRAG_NODE:
4913 case XML_NOTATION_NODE:
4914 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004915 strcat(buf, "???");
4916 if (cur->next != NULL)
4917 strcat(buf, " ");
4918 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004919 case XML_ENTITY_NODE:
4920 case XML_PI_NODE:
4921 case XML_DTD_NODE:
4922 case XML_COMMENT_NODE:
4923 case XML_ELEMENT_DECL:
4924 case XML_ATTRIBUTE_DECL:
4925 case XML_ENTITY_DECL:
4926 case XML_XINCLUDE_START:
4927 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004928 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004929 }
4930 cur = cur->next;
4931 }
4932 if (glob) strcat(buf, ")");
4933}
4934
4935/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004936 * xmlValidateElementContent:
4937 * @ctxt: the validation context
4938 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004939 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004940 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004941 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004942 *
4943 * Try to validate the content model of an element
4944 *
4945 * returns 1 if valid or 0 if not and -1 in case of error
4946 */
4947
4948static int
4949xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004950 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004951 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00004952#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00004953 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00004954#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00004955 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004956 xmlElementContentPtr cont;
4957 const xmlChar *name;
4958
4959 if (elemDecl == NULL)
4960 return(-1);
4961 cont = elemDecl->content;
4962 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004963
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004964#ifdef LIBXML_REGEXP_ENABLED
4965 /* Build the regexp associated to the content model */
4966 if (elemDecl->contModel == NULL)
4967 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4968 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004969 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004970 } else {
4971 xmlRegExecCtxtPtr exec;
4972
Daniel Veillardec498e12003-02-05 11:01:50 +00004973 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
4974 return(-1);
4975 }
Daniel Veillard01992e02002-10-09 10:20:30 +00004976 ctxt->nodeMax = 0;
4977 ctxt->nodeNr = 0;
4978 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004979 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4980 if (exec != NULL) {
4981 cur = child;
4982 while (cur != NULL) {
4983 switch (cur->type) {
4984 case XML_ENTITY_REF_NODE:
4985 /*
4986 * Push the current node to be able to roll back
4987 * and process within the entity
4988 */
4989 if ((cur->children != NULL) &&
4990 (cur->children->children != NULL)) {
4991 nodeVPush(ctxt, cur);
4992 cur = cur->children->children;
4993 continue;
4994 }
4995 break;
4996 case XML_TEXT_NODE:
4997 if (xmlIsBlankNode(cur))
4998 break;
4999 ret = 0;
5000 goto fail;
5001 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00005002 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005003 ret = 0;
5004 goto fail;
5005 case XML_ELEMENT_NODE:
5006 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005007 xmlChar fn[50];
5008 xmlChar *fullname;
5009
5010 fullname = xmlBuildQName(cur->name,
5011 cur->ns->prefix, fn, 50);
5012 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005013 ret = -1;
5014 goto fail;
5015 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005016 ret = xmlRegExecPushString(exec, fullname, NULL);
5017 if ((fullname != fn) && (fullname != cur->name))
5018 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005019 } else {
5020 ret = xmlRegExecPushString(exec, cur->name, NULL);
5021 }
5022 break;
5023 default:
5024 break;
5025 }
5026 /*
5027 * Switch to next element
5028 */
5029 cur = cur->next;
5030 while (cur == NULL) {
5031 cur = nodeVPop(ctxt);
5032 if (cur == NULL)
5033 break;
5034 cur = cur->next;
5035 }
5036 }
5037 ret = xmlRegExecPushString(exec, NULL, NULL);
5038fail:
5039 xmlRegFreeExecCtxt(exec);
5040 }
5041 }
5042#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005043 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005044 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005045 */
5046 ctxt->vstateMax = 8;
5047 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5048 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5049 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005050 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005051 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005052 }
5053 /*
5054 * The first entry in the stack is reserved to the current state
5055 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005056 ctxt->nodeMax = 0;
5057 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005058 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005059 ctxt->vstate = &ctxt->vstateTab[0];
5060 ctxt->vstateNr = 1;
5061 CONT = cont;
5062 NODE = child;
5063 DEPTH = 0;
5064 OCCURS = 0;
5065 STATE = 0;
5066 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005067 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005068 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5069 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005070 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005071 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005072 /*
5073 * An entities reference appeared at this level.
5074 * Buid a minimal representation of this node content
5075 * sufficient to run the validation process on it
5076 */
5077 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005078 cur = child;
5079 while (cur != NULL) {
5080 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005081 case XML_ENTITY_REF_NODE:
5082 /*
5083 * Push the current node to be able to roll back
5084 * and process within the entity
5085 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005086 if ((cur->children != NULL) &&
5087 (cur->children->children != NULL)) {
5088 nodeVPush(ctxt, cur);
5089 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005090 continue;
5091 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005092 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005093 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005094 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005095 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005096 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005097 case XML_CDATA_SECTION_NODE:
5098 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005099 case XML_ELEMENT_NODE:
5100 /*
5101 * Allocate a new node and minimally fills in
5102 * what's required
5103 */
5104 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5105 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005106 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005107 xmlFreeNodeList(repl);
5108 ret = -1;
5109 goto done;
5110 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005111 tmp->type = cur->type;
5112 tmp->name = cur->name;
5113 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005114 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005115 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005116 if (repl == NULL)
5117 repl = last = tmp;
5118 else {
5119 last->next = tmp;
5120 last = tmp;
5121 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005122 if (cur->type == XML_CDATA_SECTION_NODE) {
5123 /*
5124 * E59 spaces in CDATA does not match the
5125 * nonterminal S
5126 */
5127 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5128 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005129 break;
5130 default:
5131 break;
5132 }
5133 /*
5134 * Switch to next element
5135 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005136 cur = cur->next;
5137 while (cur == NULL) {
5138 cur = nodeVPop(ctxt);
5139 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005140 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005141 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005142 }
5143 }
5144
5145 /*
5146 * Relaunch the validation
5147 */
5148 ctxt->vstate = &ctxt->vstateTab[0];
5149 ctxt->vstateNr = 1;
5150 CONT = cont;
5151 NODE = repl;
5152 DEPTH = 0;
5153 OCCURS = 0;
5154 STATE = 0;
5155 ret = xmlValidateElementType(ctxt);
5156 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005157#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005158 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005159 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5160 char expr[5000];
5161 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005162
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005163 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005164 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005165 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005166#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005167 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005168 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005169 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005170#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005171 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005172
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005173 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005174 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5175 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5176 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005177 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005178 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5179 "Element content does not follow the DTD, expecting %s, got %s\n",
5180 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005181 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005182 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005183 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005184 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005185 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005186 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005187 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005188 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5189 "Element content does not follow the DTD\n",
5190 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005191 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005192 }
5193 ret = 0;
5194 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005195 if (ret == -3)
5196 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005197
Daniel Veillard23e73572002-09-19 19:56:43 +00005198#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005199done:
5200 /*
5201 * Deallocate the copy if done, and free up the validation stack
5202 */
5203 while (repl != NULL) {
5204 tmp = repl->next;
5205 xmlFree(repl);
5206 repl = tmp;
5207 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005208 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005209 if (ctxt->vstateTab != NULL) {
5210 xmlFree(ctxt->vstateTab);
5211 ctxt->vstateTab = NULL;
5212 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005213#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005214 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005215 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005216 if (ctxt->nodeTab != NULL) {
5217 xmlFree(ctxt->nodeTab);
5218 ctxt->nodeTab = NULL;
5219 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005220 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005221
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005222}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005223
Owen Taylor3473f882001-02-23 17:55:21 +00005224/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005225 * xmlValidateCdataElement:
5226 * @ctxt: the validation context
5227 * @doc: a document instance
5228 * @elem: an element instance
5229 *
5230 * Check that an element follows #CDATA
5231 *
5232 * returns 1 if valid or 0 otherwise
5233 */
5234static int
5235xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5236 xmlNodePtr elem) {
5237 int ret = 1;
5238 xmlNodePtr cur, child;
5239
Daniel Veillardceb09b92002-10-04 11:46:37 +00005240 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005241 return(0);
5242
5243 child = elem->children;
5244
5245 cur = child;
5246 while (cur != NULL) {
5247 switch (cur->type) {
5248 case XML_ENTITY_REF_NODE:
5249 /*
5250 * Push the current node to be able to roll back
5251 * and process within the entity
5252 */
5253 if ((cur->children != NULL) &&
5254 (cur->children->children != NULL)) {
5255 nodeVPush(ctxt, cur);
5256 cur = cur->children->children;
5257 continue;
5258 }
5259 break;
5260 case XML_COMMENT_NODE:
5261 case XML_PI_NODE:
5262 case XML_TEXT_NODE:
5263 case XML_CDATA_SECTION_NODE:
5264 break;
5265 default:
5266 ret = 0;
5267 goto done;
5268 }
5269 /*
5270 * Switch to next element
5271 */
5272 cur = cur->next;
5273 while (cur == NULL) {
5274 cur = nodeVPop(ctxt);
5275 if (cur == NULL)
5276 break;
5277 cur = cur->next;
5278 }
5279 }
5280done:
5281 ctxt->nodeMax = 0;
5282 ctxt->nodeNr = 0;
5283 if (ctxt->nodeTab != NULL) {
5284 xmlFree(ctxt->nodeTab);
5285 ctxt->nodeTab = NULL;
5286 }
5287 return(ret);
5288}
5289
5290/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005291 * xmlValidateCheckMixed:
5292 * @ctxt: the validation context
5293 * @cont: the mixed content model
5294 * @qname: the qualified name as appearing in the serialization
5295 *
5296 * Check if the given node is part of the content model.
5297 *
5298 * Returns 1 if yes, 0 if no, -1 in case of error
5299 */
5300static int
William M. Brackedb65a72004-02-06 07:36:04 +00005301xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005302 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005303 const xmlChar *name;
5304 int plen;
5305 name = xmlSplitQName3(qname, &plen);
5306
5307 if (name == NULL) {
5308 while (cont != NULL) {
5309 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5310 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5311 return(1);
5312 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5313 (cont->c1 != NULL) &&
5314 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5315 if ((cont->c1->prefix == NULL) &&
5316 (xmlStrEqual(cont->c1->name, qname)))
5317 return(1);
5318 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5319 (cont->c1 == NULL) ||
5320 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005321 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5322 "Internal: MIXED struct corrupted\n",
5323 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005324 break;
5325 }
5326 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005327 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005328 } else {
5329 while (cont != NULL) {
5330 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5331 if ((cont->prefix != NULL) &&
5332 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5333 (xmlStrEqual(cont->name, name)))
5334 return(1);
5335 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5336 (cont->c1 != NULL) &&
5337 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5338 if ((cont->c1->prefix != NULL) &&
5339 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5340 (xmlStrEqual(cont->c1->name, name)))
5341 return(1);
5342 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5343 (cont->c1 == NULL) ||
5344 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005345 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5346 "Internal: MIXED struct corrupted\n",
5347 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005348 break;
5349 }
5350 cont = cont->c2;
5351 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005352 }
5353 return(0);
5354}
5355
5356/**
5357 * xmlValidGetElemDecl:
5358 * @ctxt: the validation context
5359 * @doc: a document instance
5360 * @elem: an element instance
5361 * @extsubset: pointer, (out) indicate if the declaration was found
5362 * in the external subset.
5363 *
5364 * Finds a declaration associated to an element in the document.
5365 *
5366 * returns the pointer to the declaration or NULL if not found.
5367 */
5368static xmlElementPtr
5369xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5370 xmlNodePtr elem, int *extsubset) {
5371 xmlElementPtr elemDecl = NULL;
5372 const xmlChar *prefix = NULL;
5373
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005374 if ((ctxt == NULL) || (doc == NULL) ||
5375 (elem == NULL) || (elem->name == NULL))
5376 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005377 if (extsubset != NULL)
5378 *extsubset = 0;
5379
5380 /*
5381 * Fetch the declaration for the qualified name
5382 */
5383 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5384 prefix = elem->ns->prefix;
5385
5386 if (prefix != NULL) {
5387 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5388 elem->name, prefix);
5389 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5390 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5391 elem->name, prefix);
5392 if ((elemDecl != NULL) && (extsubset != NULL))
5393 *extsubset = 1;
5394 }
5395 }
5396
5397 /*
5398 * Fetch the declaration for the non qualified name
5399 * This is "non-strict" validation should be done on the
5400 * full QName but in that case being flexible makes sense.
5401 */
5402 if (elemDecl == NULL) {
5403 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5404 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5405 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5406 if ((elemDecl != NULL) && (extsubset != NULL))
5407 *extsubset = 1;
5408 }
5409 }
5410 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005411 xmlErrValidNode(ctxt, elem,
5412 XML_DTD_UNKNOWN_ELEM,
5413 "No declaration for element %s\n",
5414 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005415 }
5416 return(elemDecl);
5417}
5418
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005419#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005420/**
5421 * xmlValidatePushElement:
5422 * @ctxt: the validation context
5423 * @doc: a document instance
5424 * @elem: an element instance
5425 * @qname: the qualified name as appearing in the serialization
5426 *
5427 * Push a new element start on the validation stack.
5428 *
5429 * returns 1 if no validation problem was found or 0 otherwise
5430 */
5431int
5432xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5433 xmlNodePtr elem, const xmlChar *qname) {
5434 int ret = 1;
5435 xmlElementPtr eDecl;
5436 int extsubset = 0;
5437
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005438 if (ctxt == NULL)
5439 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005440/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005441 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5442 xmlValidStatePtr state = ctxt->vstate;
5443 xmlElementPtr elemDecl;
5444
5445 /*
5446 * Check the new element agaisnt the content model of the new elem.
5447 */
5448 if (state->elemDecl != NULL) {
5449 elemDecl = state->elemDecl;
5450
5451 switch(elemDecl->etype) {
5452 case XML_ELEMENT_TYPE_UNDEFINED:
5453 ret = 0;
5454 break;
5455 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005456 xmlErrValidNode(ctxt, state->node,
5457 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005458 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005459 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005460 ret = 0;
5461 break;
5462 case XML_ELEMENT_TYPE_ANY:
5463 /* I don't think anything is required then */
5464 break;
5465 case XML_ELEMENT_TYPE_MIXED:
5466 /* simple case of declared as #PCDATA */
5467 if ((elemDecl->content != NULL) &&
5468 (elemDecl->content->type ==
5469 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005470 xmlErrValidNode(ctxt, state->node,
5471 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005472 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005473 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005474 ret = 0;
5475 } else {
5476 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5477 qname);
5478 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005479 xmlErrValidNode(ctxt, state->node,
5480 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005481 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005482 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005483 }
5484 }
5485 break;
5486 case XML_ELEMENT_TYPE_ELEMENT:
5487 /*
5488 * TODO:
5489 * VC: Standalone Document Declaration
5490 * - element types with element content, if white space
5491 * occurs directly within any instance of those types.
5492 */
5493 if (state->exec != NULL) {
5494 ret = xmlRegExecPushString(state->exec, qname, NULL);
5495 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005496 xmlErrValidNode(ctxt, state->node,
5497 XML_DTD_CONTENT_MODEL,
5498 "Element %s content does not follow the DTD, Misplaced %s\n",
5499 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005500 ret = 0;
5501 } else {
5502 ret = 1;
5503 }
5504 }
5505 break;
5506 }
5507 }
5508 }
5509 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5510 vstateVPush(ctxt, eDecl, elem);
5511 return(ret);
5512}
5513
5514/**
5515 * xmlValidatePushCData:
5516 * @ctxt: the validation context
5517 * @data: some character data read
5518 * @len: the lenght of the data
5519 *
5520 * check the CData parsed for validation in the current stack
5521 *
5522 * returns 1 if no validation problem was found or 0 otherwise
5523 */
5524int
5525xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5526 int ret = 1;
5527
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005528/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005529 if (ctxt == NULL)
5530 return(0);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005531 if (len <= 0)
5532 return(ret);
5533 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5534 xmlValidStatePtr state = ctxt->vstate;
5535 xmlElementPtr elemDecl;
5536
5537 /*
5538 * Check the new element agaisnt the content model of the new elem.
5539 */
5540 if (state->elemDecl != NULL) {
5541 elemDecl = state->elemDecl;
5542
5543 switch(elemDecl->etype) {
5544 case XML_ELEMENT_TYPE_UNDEFINED:
5545 ret = 0;
5546 break;
5547 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005548 xmlErrValidNode(ctxt, state->node,
5549 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005550 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005551 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005552 ret = 0;
5553 break;
5554 case XML_ELEMENT_TYPE_ANY:
5555 break;
5556 case XML_ELEMENT_TYPE_MIXED:
5557 break;
5558 case XML_ELEMENT_TYPE_ELEMENT:
5559 if (len > 0) {
5560 int i;
5561
5562 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005563 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005564 xmlErrValidNode(ctxt, state->node,
5565 XML_DTD_CONTENT_MODEL,
5566 "Element %s content does not follow the DTD, Text not allowed\n",
5567 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005568 ret = 0;
5569 goto done;
5570 }
5571 }
5572 /*
5573 * TODO:
5574 * VC: Standalone Document Declaration
5575 * element types with element content, if white space
5576 * occurs directly within any instance of those types.
5577 */
5578 }
5579 break;
5580 }
5581 }
5582 }
5583done:
5584 return(ret);
5585}
5586
5587/**
5588 * xmlValidatePopElement:
5589 * @ctxt: the validation context
5590 * @doc: a document instance
5591 * @elem: an element instance
5592 * @qname: the qualified name as appearing in the serialization
5593 *
5594 * Pop the element end from the validation stack.
5595 *
5596 * returns 1 if no validation problem was found or 0 otherwise
5597 */
5598int
5599xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005600 xmlNodePtr elem ATTRIBUTE_UNUSED,
5601 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005602 int ret = 1;
5603
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005604 if (ctxt == NULL)
5605 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005606/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005607 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5608 xmlValidStatePtr state = ctxt->vstate;
5609 xmlElementPtr elemDecl;
5610
5611 /*
5612 * Check the new element agaisnt the content model of the new elem.
5613 */
5614 if (state->elemDecl != NULL) {
5615 elemDecl = state->elemDecl;
5616
5617 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5618 if (state->exec != NULL) {
5619 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5620 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005621 xmlErrValidNode(ctxt, state->node,
5622 XML_DTD_CONTENT_MODEL,
5623 "Element %s content does not follow the DTD, Expecting more child\n",
5624 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005625 } else {
5626 /*
5627 * previous validation errors should not generate
5628 * a new one here
5629 */
5630 ret = 1;
5631 }
5632 }
5633 }
5634 }
5635 vstateVPop(ctxt);
5636 }
5637 return(ret);
5638}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005639#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005640
5641/**
Owen Taylor3473f882001-02-23 17:55:21 +00005642 * xmlValidateOneElement:
5643 * @ctxt: the validation context
5644 * @doc: a document instance
5645 * @elem: an element instance
5646 *
5647 * Try to validate a single element and it's attributes,
5648 * basically it does the following checks as described by the
5649 * XML-1.0 recommendation:
5650 * - [ VC: Element Valid ]
5651 * - [ VC: Required Attribute ]
5652 * Then call xmlValidateOneAttribute() for each attribute present.
5653 *
5654 * The ID/IDREF checkings are done separately
5655 *
5656 * returns 1 if valid or 0 otherwise
5657 */
5658
5659int
5660xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5661 xmlNodePtr elem) {
5662 xmlElementPtr elemDecl = NULL;
5663 xmlElementContentPtr cont;
5664 xmlAttributePtr attr;
5665 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005666 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005667 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005668 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005669
5670 CHECK_DTD;
5671
5672 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005673 switch (elem->type) {
5674 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005675 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5676 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005677 return(0);
5678 case XML_TEXT_NODE:
5679 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005680 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5681 "Text element has children !\n",
5682 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005683 return(0);
5684 }
5685 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005686 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5687 "Text element has attribute !\n",
5688 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005689 return(0);
5690 }
5691 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005692 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5693 "Text element has namespace !\n",
5694 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005695 return(0);
5696 }
5697 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005698 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5699 "Text element has namespace !\n",
5700 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005701 return(0);
5702 }
5703 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005704 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5705 "Text element has no content !\n",
5706 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005707 return(0);
5708 }
5709 return(1);
5710 case XML_XINCLUDE_START:
5711 case XML_XINCLUDE_END:
5712 return(1);
5713 case XML_CDATA_SECTION_NODE:
5714 case XML_ENTITY_REF_NODE:
5715 case XML_PI_NODE:
5716 case XML_COMMENT_NODE:
5717 return(1);
5718 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005719 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5720 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005721 return(0);
5722 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005723 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5724 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005725 return(0);
5726 case XML_DOCUMENT_NODE:
5727 case XML_DOCUMENT_TYPE_NODE:
5728 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005729 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5730 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005731 return(0);
5732 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005733 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5734 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005735 return(0);
5736 case XML_ELEMENT_NODE:
5737 break;
5738 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005739 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5740 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005741 return(0);
5742 }
Owen Taylor3473f882001-02-23 17:55:21 +00005743
5744 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005745 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005746 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005747 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5748 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005749 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005750
Daniel Veillardea7751d2002-12-20 00:16:24 +00005751 /*
5752 * If vstateNr is not zero that means continuous validation is
5753 * activated, do not try to check the content model at that level.
5754 */
5755 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005756 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005757 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005758 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005759 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5760 "No declaration for element %s\n",
5761 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005762 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005763 case XML_ELEMENT_TYPE_EMPTY:
5764 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005765 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005766 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005767 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005768 ret = 0;
5769 }
5770 break;
5771 case XML_ELEMENT_TYPE_ANY:
5772 /* I don't think anything is required then */
5773 break;
5774 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005775
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005776 /* simple case of declared as #PCDATA */
5777 if ((elemDecl->content != NULL) &&
5778 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5779 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5780 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005781 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005782 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005783 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005784 }
5785 break;
5786 }
Owen Taylor3473f882001-02-23 17:55:21 +00005787 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005788 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005789 while (child != NULL) {
5790 if (child->type == XML_ELEMENT_NODE) {
5791 name = child->name;
5792 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005793 xmlChar fn[50];
5794 xmlChar *fullname;
5795
5796 fullname = xmlBuildQName(child->name, child->ns->prefix,
5797 fn, 50);
5798 if (fullname == NULL)
5799 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005800 cont = elemDecl->content;
5801 while (cont != NULL) {
5802 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005803 if (xmlStrEqual(cont->name, fullname))
5804 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005805 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5806 (cont->c1 != NULL) &&
5807 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005808 if (xmlStrEqual(cont->c1->name, fullname))
5809 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005810 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5811 (cont->c1 == NULL) ||
5812 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005813 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5814 "Internal: MIXED struct corrupted\n",
5815 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005816 break;
5817 }
5818 cont = cont->c2;
5819 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005820 if ((fullname != fn) && (fullname != child->name))
5821 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005822 if (cont != NULL)
5823 goto child_ok;
5824 }
5825 cont = elemDecl->content;
5826 while (cont != NULL) {
5827 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5828 if (xmlStrEqual(cont->name, name)) break;
5829 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5830 (cont->c1 != NULL) &&
5831 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5832 if (xmlStrEqual(cont->c1->name, name)) break;
5833 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5834 (cont->c1 == NULL) ||
5835 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005836 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5837 "Internal: MIXED struct corrupted\n",
5838 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005839 break;
5840 }
5841 cont = cont->c2;
5842 }
5843 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005844 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00005845 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005846 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005847 ret = 0;
5848 }
5849 }
5850child_ok:
5851 child = child->next;
5852 }
5853 break;
5854 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005855 if ((doc->standalone == 1) && (extsubset == 1)) {
5856 /*
5857 * VC: Standalone Document Declaration
5858 * - element types with element content, if white space
5859 * occurs directly within any instance of those types.
5860 */
5861 child = elem->children;
5862 while (child != NULL) {
5863 if (child->type == XML_TEXT_NODE) {
5864 const xmlChar *content = child->content;
5865
William M. Brack76e95df2003-10-18 16:20:14 +00005866 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005867 content++;
5868 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005869 xmlErrValidNode(ctxt, elem,
5870 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005871"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005872 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005873 ret = 0;
5874 break;
5875 }
5876 }
5877 child =child->next;
5878 }
5879 }
Owen Taylor3473f882001-02-23 17:55:21 +00005880 child = elem->children;
5881 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005882 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005883 if (tmp <= 0)
5884 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005885 break;
5886 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005887 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00005888
5889 /* [ VC: Required Attribute ] */
5890 attr = elemDecl->attributes;
5891 while (attr != NULL) {
5892 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005893 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005894
Daniel Veillarde4301c82002-02-13 13:32:35 +00005895 if ((attr->prefix == NULL) &&
5896 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5897 xmlNsPtr ns;
5898
5899 ns = elem->nsDef;
5900 while (ns != NULL) {
5901 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005902 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005903 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00005904 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005905 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5906 xmlNsPtr ns;
5907
5908 ns = elem->nsDef;
5909 while (ns != NULL) {
5910 if (xmlStrEqual(attr->name, ns->prefix))
5911 goto found;
5912 ns = ns->next;
5913 }
5914 } else {
5915 xmlAttrPtr attrib;
5916
5917 attrib = elem->properties;
5918 while (attrib != NULL) {
5919 if (xmlStrEqual(attrib->name, attr->name)) {
5920 if (attr->prefix != NULL) {
5921 xmlNsPtr nameSpace = attrib->ns;
5922
5923 if (nameSpace == NULL)
5924 nameSpace = elem->ns;
5925 /*
5926 * qualified names handling is problematic, having a
5927 * different prefix should be possible but DTDs don't
5928 * allow to define the URI instead of the prefix :-(
5929 */
5930 if (nameSpace == NULL) {
5931 if (qualified < 0)
5932 qualified = 0;
5933 } else if (!xmlStrEqual(nameSpace->prefix,
5934 attr->prefix)) {
5935 if (qualified < 1)
5936 qualified = 1;
5937 } else
5938 goto found;
5939 } else {
5940 /*
5941 * We should allow applications to define namespaces
5942 * for their application even if the DTD doesn't
5943 * carry one, otherwise, basically we would always
5944 * break.
5945 */
5946 goto found;
5947 }
5948 }
5949 attrib = attrib->next;
5950 }
Owen Taylor3473f882001-02-23 17:55:21 +00005951 }
5952 if (qualified == -1) {
5953 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005954 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005955 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005956 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005957 ret = 0;
5958 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005959 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005960 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005961 elem->name, attr->prefix,attr->name);
5962 ret = 0;
5963 }
5964 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005965 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005966 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005967 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005968 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005969 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005970 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005971 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005972 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005973 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5974 /*
5975 * Special tests checking #FIXED namespace declarations
5976 * have the right value since this is not done as an
5977 * attribute checking
5978 */
5979 if ((attr->prefix == NULL) &&
5980 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5981 xmlNsPtr ns;
5982
5983 ns = elem->nsDef;
5984 while (ns != NULL) {
5985 if (ns->prefix == NULL) {
5986 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005987 xmlErrValidNode(ctxt, elem,
5988 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00005989 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005990 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005991 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005992 }
5993 goto found;
5994 }
5995 ns = ns->next;
5996 }
5997 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5998 xmlNsPtr ns;
5999
6000 ns = elem->nsDef;
6001 while (ns != NULL) {
6002 if (xmlStrEqual(attr->name, ns->prefix)) {
6003 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006004 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006005 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006006 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006007 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006008 }
6009 goto found;
6010 }
6011 ns = ns->next;
6012 }
6013 }
Owen Taylor3473f882001-02-23 17:55:21 +00006014 }
6015found:
6016 attr = attr->nexth;
6017 }
6018 return(ret);
6019}
6020
6021/**
6022 * xmlValidateRoot:
6023 * @ctxt: the validation context
6024 * @doc: a document instance
6025 *
6026 * Try to validate a the root element
6027 * basically it does the following check as described by the
6028 * XML-1.0 recommendation:
6029 * - [ VC: Root Element Type ]
6030 * it doesn't try to recurse or apply other check to the element
6031 *
6032 * returns 1 if valid or 0 otherwise
6033 */
6034
6035int
6036xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6037 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006038 int ret;
6039
Owen Taylor3473f882001-02-23 17:55:21 +00006040 if (doc == NULL) return(0);
6041
6042 root = xmlDocGetRootElement(doc);
6043 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006044 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6045 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006046 return(0);
6047 }
6048
6049 /*
6050 * When doing post validation against a separate DTD, those may
6051 * no internal subset has been generated
6052 */
6053 if ((doc->intSubset != NULL) &&
6054 (doc->intSubset->name != NULL)) {
6055 /*
6056 * Check first the document root against the NQName
6057 */
6058 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6059 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006060 xmlChar fn[50];
6061 xmlChar *fullname;
6062
6063 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6064 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006065 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006066 return(0);
6067 }
6068 ret = xmlStrEqual(doc->intSubset->name, fullname);
6069 if ((fullname != fn) && (fullname != root->name))
6070 xmlFree(fullname);
6071 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006072 goto name_ok;
6073 }
6074 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6075 (xmlStrEqual(root->name, BAD_CAST "html")))
6076 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006077 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6078 "root and DTD name do not match '%s' and '%s'\n",
6079 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006080 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006081 }
6082 }
6083name_ok:
6084 return(1);
6085}
6086
6087
6088/**
6089 * xmlValidateElement:
6090 * @ctxt: the validation context
6091 * @doc: a document instance
6092 * @elem: an element instance
6093 *
6094 * Try to validate the subtree under an element
6095 *
6096 * returns 1 if valid or 0 otherwise
6097 */
6098
6099int
6100xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6101 xmlNodePtr child;
6102 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006103 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006104 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006105 int ret = 1;
6106
6107 if (elem == NULL) return(0);
6108
6109 /*
6110 * XInclude elements were added after parsing in the infoset,
6111 * they don't really mean anything validation wise.
6112 */
6113 if ((elem->type == XML_XINCLUDE_START) ||
6114 (elem->type == XML_XINCLUDE_END))
6115 return(1);
6116
6117 CHECK_DTD;
6118
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006119 /*
6120 * Entities references have to be handled separately
6121 */
6122 if (elem->type == XML_ENTITY_REF_NODE) {
6123 return(1);
6124 }
6125
Owen Taylor3473f882001-02-23 17:55:21 +00006126 ret &= xmlValidateOneElement(ctxt, doc, elem);
6127 attr = elem->properties;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006128 while (attr != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006129 value = xmlNodeListGetString(doc, attr->children, 0);
6130 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6131 if (value != NULL)
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006132 xmlFree((char *)value);
Owen Taylor3473f882001-02-23 17:55:21 +00006133 attr= attr->next;
6134 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006135 ns = elem->nsDef;
6136 while (ns != NULL) {
Daniel Veillard1f5c9892003-12-29 17:09:55 +00006137 if (elem->ns == NULL)
6138 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6139 ns, ns->href);
6140 else
6141 ret &= xmlValidateOneNamespace(ctxt, doc, elem, elem->ns->prefix,
6142 ns, ns->href);
Daniel Veillarde133dd82003-10-30 10:42:20 +00006143 ns = ns->next;
6144 }
Owen Taylor3473f882001-02-23 17:55:21 +00006145 child = elem->children;
6146 while (child != NULL) {
6147 ret &= xmlValidateElement(ctxt, doc, child);
6148 child = child->next;
6149 }
6150
6151 return(ret);
6152}
6153
Daniel Veillard8730c562001-02-26 10:49:57 +00006154/**
6155 * xmlValidateRef:
6156 * @ref: A reference to be validated
6157 * @ctxt: Validation context
6158 * @name: Name of ID we are searching for
6159 *
6160 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006161static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006162xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006163 const xmlChar *name) {
6164 xmlAttrPtr id;
6165 xmlAttrPtr attr;
6166
6167 if (ref == NULL)
6168 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006169 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006170 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006171 attr = ref->attr;
6172 if (attr == NULL) {
6173 xmlChar *dup, *str = NULL, *cur, save;
6174
6175 dup = xmlStrdup(name);
6176 if (dup == NULL) {
6177 ctxt->valid = 0;
6178 return;
6179 }
6180 cur = dup;
6181 while (*cur != 0) {
6182 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006183 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006184 save = *cur;
6185 *cur = 0;
6186 id = xmlGetID(ctxt->doc, str);
6187 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006188 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006189 "attribute %s line %d references an unknown ID \"%s\"\n",
6190 ref->name, ref->lineno, str);
6191 ctxt->valid = 0;
6192 }
6193 if (save == 0)
6194 break;
6195 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006196 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006197 }
6198 xmlFree(dup);
6199 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006200 id = xmlGetID(ctxt->doc, name);
6201 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006202 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006203 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006204 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006205 ctxt->valid = 0;
6206 }
6207 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6208 xmlChar *dup, *str = NULL, *cur, save;
6209
6210 dup = xmlStrdup(name);
6211 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006212 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006213 ctxt->valid = 0;
6214 return;
6215 }
6216 cur = dup;
6217 while (*cur != 0) {
6218 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006219 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006220 save = *cur;
6221 *cur = 0;
6222 id = xmlGetID(ctxt->doc, str);
6223 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006224 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006225 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006226 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006227 ctxt->valid = 0;
6228 }
6229 if (save == 0)
6230 break;
6231 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006232 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006233 }
6234 xmlFree(dup);
6235 }
6236}
6237
6238/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006239 * xmlWalkValidateList:
6240 * @data: Contents of current link
6241 * @user: Value supplied by the user
6242 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006243 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006244 */
6245static int
6246xmlWalkValidateList(const void *data, const void *user)
6247{
6248 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6249 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6250 return 1;
6251}
6252
6253/**
6254 * xmlValidateCheckRefCallback:
6255 * @ref_list: List of references
6256 * @ctxt: Validation context
6257 * @name: Name of ID we are searching for
6258 *
6259 */
6260static void
6261xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6262 const xmlChar *name) {
6263 xmlValidateMemo memo;
6264
6265 if (ref_list == NULL)
6266 return;
6267 memo.ctxt = ctxt;
6268 memo.name = name;
6269
6270 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6271
6272}
6273
6274/**
Owen Taylor3473f882001-02-23 17:55:21 +00006275 * xmlValidateDocumentFinal:
6276 * @ctxt: the validation context
6277 * @doc: a document instance
6278 *
6279 * Does the final step for the document validation once all the
6280 * incremental validation steps have been completed
6281 *
6282 * basically it does the following checks described by the XML Rec
6283 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006284 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006285 *
6286 * returns 1 if valid or 0 otherwise
6287 */
6288
6289int
6290xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6291 xmlRefTablePtr table;
6292
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006293 if (ctxt == NULL)
6294 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006295 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006296 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6297 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006298 return(0);
6299 }
6300
6301 /*
6302 * Check all the NOTATION/NOTATIONS attributes
6303 */
6304 /*
6305 * Check all the ENTITY/ENTITIES attributes definition for validity
6306 */
6307 /*
6308 * Check all the IDREF/IDREFS attributes definition for validity
6309 */
6310 table = (xmlRefTablePtr) doc->refs;
6311 ctxt->doc = doc;
6312 ctxt->valid = 1;
6313 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6314 return(ctxt->valid);
6315}
6316
6317/**
6318 * xmlValidateDtd:
6319 * @ctxt: the validation context
6320 * @doc: a document instance
6321 * @dtd: a dtd instance
6322 *
6323 * Try to validate the document against the dtd instance
6324 *
William M. Brack367df6e2004-10-23 18:14:36 +00006325 * Basically it does check all the definitions in the DtD.
6326 * Note the the internal subset (if present) is de-coupled
6327 * (i.e. not used), which could give problems if ID or IDREF
6328 * is present.
Owen Taylor3473f882001-02-23 17:55:21 +00006329 *
6330 * returns 1 if valid or 0 otherwise
6331 */
6332
6333int
6334xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6335 int ret;
William M. Brack367df6e2004-10-23 18:14:36 +00006336 xmlDtdPtr oldExt, oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006337 xmlNodePtr root;
6338
6339 if (dtd == NULL) return(0);
6340 if (doc == NULL) return(0);
6341 oldExt = doc->extSubset;
William M. Brack367df6e2004-10-23 18:14:36 +00006342 oldInt = doc->intSubset;
Owen Taylor3473f882001-02-23 17:55:21 +00006343 doc->extSubset = dtd;
William M. Brack367df6e2004-10-23 18:14:36 +00006344 doc->intSubset = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006345 ret = xmlValidateRoot(ctxt, doc);
6346 if (ret == 0) {
6347 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006348 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006349 return(ret);
6350 }
6351 if (doc->ids != NULL) {
6352 xmlFreeIDTable(doc->ids);
6353 doc->ids = NULL;
6354 }
6355 if (doc->refs != NULL) {
6356 xmlFreeRefTable(doc->refs);
6357 doc->refs = NULL;
6358 }
6359 root = xmlDocGetRootElement(doc);
6360 ret = xmlValidateElement(ctxt, doc, root);
6361 ret &= xmlValidateDocumentFinal(ctxt, doc);
6362 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006363 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006364 return(ret);
6365}
6366
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006367static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006368xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6369 const xmlChar *name ATTRIBUTE_UNUSED) {
6370 if (cur == NULL)
6371 return;
6372 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6373 xmlChar *notation = cur->content;
6374
Daniel Veillard878eab02002-02-19 13:46:09 +00006375 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006376 int ret;
6377
6378 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6379 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006380 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006381 }
6382 }
6383 }
6384}
6385
6386static void
Owen Taylor3473f882001-02-23 17:55:21 +00006387xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006388 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006389 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006390 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006391 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006392
Owen Taylor3473f882001-02-23 17:55:21 +00006393 if (cur == NULL)
6394 return;
6395 switch (cur->atype) {
6396 case XML_ATTRIBUTE_CDATA:
6397 case XML_ATTRIBUTE_ID:
6398 case XML_ATTRIBUTE_IDREF :
6399 case XML_ATTRIBUTE_IDREFS:
6400 case XML_ATTRIBUTE_NMTOKEN:
6401 case XML_ATTRIBUTE_NMTOKENS:
6402 case XML_ATTRIBUTE_ENUMERATION:
6403 break;
6404 case XML_ATTRIBUTE_ENTITY:
6405 case XML_ATTRIBUTE_ENTITIES:
6406 case XML_ATTRIBUTE_NOTATION:
6407 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006408
6409 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6410 cur->atype, cur->defaultValue);
6411 if ((ret == 0) && (ctxt->valid == 1))
6412 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006413 }
6414 if (cur->tree != NULL) {
6415 xmlEnumerationPtr tree = cur->tree;
6416 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006417 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006418 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006419 if ((ret == 0) && (ctxt->valid == 1))
6420 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006421 tree = tree->next;
6422 }
6423 }
6424 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006425 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6426 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006427 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006428 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006429 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006430 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006431 return;
6432 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006433
6434 if (doc != NULL)
6435 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6436 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006437 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006438 if ((elem == NULL) && (cur->parent != NULL) &&
6439 (cur->parent->type == XML_DTD_NODE))
6440 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006441 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006442 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006443 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006444 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006445 return;
6446 }
6447 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006448 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006449 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006450 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006451 ctxt->valid = 0;
6452 }
6453 }
Owen Taylor3473f882001-02-23 17:55:21 +00006454}
6455
6456/**
6457 * xmlValidateDtdFinal:
6458 * @ctxt: the validation context
6459 * @doc: a document instance
6460 *
6461 * Does the final step for the dtds validation once all the
6462 * subsets have been parsed
6463 *
6464 * basically it does the following checks described by the XML Rec
6465 * - check that ENTITY and ENTITIES type attributes default or
6466 * possible values matches one of the defined entities.
6467 * - check that NOTATION type attributes default or
6468 * possible values matches one of the defined notations.
6469 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006470 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006471 */
6472
6473int
6474xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006475 xmlDtdPtr dtd;
6476 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006477 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006478
6479 if (doc == NULL) return(0);
6480 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6481 return(0);
6482 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006483 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006484 dtd = doc->intSubset;
6485 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6486 table = (xmlAttributeTablePtr) dtd->attributes;
6487 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006488 }
6489 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006490 entities = (xmlEntitiesTablePtr) dtd->entities;
6491 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6492 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006493 }
6494 dtd = doc->extSubset;
6495 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6496 table = (xmlAttributeTablePtr) dtd->attributes;
6497 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006498 }
6499 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006500 entities = (xmlEntitiesTablePtr) dtd->entities;
6501 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6502 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006503 }
6504 return(ctxt->valid);
6505}
6506
6507/**
6508 * xmlValidateDocument:
6509 * @ctxt: the validation context
6510 * @doc: a document instance
6511 *
6512 * Try to validate the document instance
6513 *
6514 * basically it does the all the checks described by the XML Rec
6515 * i.e. validates the internal and external subset (if present)
6516 * and validate the document tree.
6517 *
6518 * returns 1 if valid or 0 otherwise
6519 */
6520
6521int
6522xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6523 int ret;
6524 xmlNodePtr root;
6525
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006526 if (doc == NULL)
6527 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006528 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006529 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6530 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006531 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006532 }
Owen Taylor3473f882001-02-23 17:55:21 +00006533 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6534 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
William M. Brack8c22f9f2004-08-06 16:23:27 +00006535 xmlChar *sysID;
6536 if (doc->intSubset->SystemID != NULL) {
William M. Brackbebe7302004-08-05 06:46:47 +00006537 sysID = xmlBuildURI(doc->intSubset->SystemID,
6538 doc->URL);
William M. Brack8c22f9f2004-08-06 16:23:27 +00006539 if (sysID == NULL) {
6540 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6541 "Could not build URI for external subset \"%s\"\n",
6542 (const char *) doc->intSubset->SystemID);
6543 return 0;
6544 }
6545 } else
William M. Brackbebe7302004-08-05 06:46:47 +00006546 sysID = NULL;
William M. Brack8c22f9f2004-08-06 16:23:27 +00006547 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
William M. Brackbebe7302004-08-05 06:46:47 +00006548 (const xmlChar *)sysID);
William M. Brackbebe7302004-08-05 06:46:47 +00006549 if (sysID != NULL)
6550 xmlFree(sysID);
Owen Taylor3473f882001-02-23 17:55:21 +00006551 if (doc->extSubset == NULL) {
6552 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006553 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006554 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006555 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006556 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006557 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006558 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006559 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006560 }
6561 return(0);
6562 }
6563 }
6564
6565 if (doc->ids != NULL) {
6566 xmlFreeIDTable(doc->ids);
6567 doc->ids = NULL;
6568 }
6569 if (doc->refs != NULL) {
6570 xmlFreeRefTable(doc->refs);
6571 doc->refs = NULL;
6572 }
6573 ret = xmlValidateDtdFinal(ctxt, doc);
6574 if (!xmlValidateRoot(ctxt, doc)) return(0);
6575
6576 root = xmlDocGetRootElement(doc);
6577 ret &= xmlValidateElement(ctxt, doc, root);
6578 ret &= xmlValidateDocumentFinal(ctxt, doc);
6579 return(ret);
6580}
6581
Owen Taylor3473f882001-02-23 17:55:21 +00006582/************************************************************************
6583 * *
6584 * Routines for dynamic validation editing *
6585 * *
6586 ************************************************************************/
6587
6588/**
6589 * xmlValidGetPotentialChildren:
6590 * @ctree: an element content tree
6591 * @list: an array to store the list of child names
6592 * @len: a pointer to the number of element in the list
6593 * @max: the size of the array
6594 *
6595 * Build/extend a list of potential children allowed by the content tree
6596 *
6597 * returns the number of element in the list, or -1 in case of error.
6598 */
6599
6600int
6601xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6602 int *len, int max) {
6603 int i;
6604
6605 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6606 return(-1);
6607 if (*len >= max) return(*len);
6608
6609 switch (ctree->type) {
6610 case XML_ELEMENT_CONTENT_PCDATA:
6611 for (i = 0; i < *len;i++)
6612 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6613 list[(*len)++] = BAD_CAST "#PCDATA";
6614 break;
6615 case XML_ELEMENT_CONTENT_ELEMENT:
6616 for (i = 0; i < *len;i++)
6617 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6618 list[(*len)++] = ctree->name;
6619 break;
6620 case XML_ELEMENT_CONTENT_SEQ:
6621 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6622 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6623 break;
6624 case XML_ELEMENT_CONTENT_OR:
6625 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6626 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6627 break;
6628 }
6629
6630 return(*len);
6631}
6632
William M. Brack9333cc22004-06-24 08:33:40 +00006633/*
6634 * Dummy function to suppress messages while we try out valid elements
6635 */
6636static void xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
6637 const char *msg ATTRIBUTE_UNUSED, ...) {
6638 return;
6639}
6640
Owen Taylor3473f882001-02-23 17:55:21 +00006641/**
6642 * xmlValidGetValidElements:
6643 * @prev: an element to insert after
6644 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006645 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006646 * @max: the size of the array
6647 *
6648 * This function returns the list of authorized children to insert
6649 * within an existing tree while respecting the validity constraints
6650 * forced by the Dtd. The insertion point is defined using @prev and
6651 * @next in the following ways:
6652 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6653 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6654 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6655 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6656 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6657 *
6658 * pointers to the element names are inserted at the beginning of the array
6659 * and do not need to be freed.
6660 *
6661 * returns the number of element in the list, or -1 in case of error. If
6662 * the function returns the value @max the caller is invited to grow the
6663 * receiving array and retry.
6664 */
6665
6666int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006667xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006668 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006669 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006670 int nb_valid_elements = 0;
6671 const xmlChar *elements[256];
6672 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006673 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006674
6675 xmlNode *ref_node;
6676 xmlNode *parent;
6677 xmlNode *test_node;
6678
6679 xmlNode *prev_next;
6680 xmlNode *next_prev;
6681 xmlNode *parent_childs;
6682 xmlNode *parent_last;
6683
6684 xmlElement *element_desc;
6685
6686 if (prev == NULL && next == NULL)
6687 return(-1);
6688
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006689 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006690 if (max <= 0) return(-1);
6691
William M. Brack9333cc22004-06-24 08:33:40 +00006692 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6693 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6694
Owen Taylor3473f882001-02-23 17:55:21 +00006695 nb_valid_elements = 0;
6696 ref_node = prev ? prev : next;
6697 parent = ref_node->parent;
6698
6699 /*
6700 * Retrieves the parent element declaration
6701 */
6702 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6703 parent->name);
6704 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6705 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6706 parent->name);
6707 if (element_desc == NULL) return(-1);
6708
6709 /*
6710 * Do a backup of the current tree structure
6711 */
6712 prev_next = prev ? prev->next : NULL;
6713 next_prev = next ? next->prev : NULL;
6714 parent_childs = parent->children;
6715 parent_last = parent->last;
6716
6717 /*
6718 * Creates a dummy node and insert it into the tree
6719 */
Daniel Veillard95ddcd32004-10-26 21:53:55 +00006720 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006721 test_node->parent = parent;
6722 test_node->prev = prev;
6723 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006724 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006725
6726 if (prev) prev->next = test_node;
6727 else parent->children = test_node;
6728
6729 if (next) next->prev = test_node;
6730 else parent->last = test_node;
6731
6732 /*
6733 * Insert each potential child node and check if the parent is
6734 * still valid
6735 */
6736 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6737 elements, &nb_elements, 256);
6738
6739 for (i = 0;i < nb_elements;i++) {
6740 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006741 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006742 int j;
6743
6744 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006745 if (xmlStrEqual(elements[i], names[j])) break;
6746 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00006747 if (nb_valid_elements >= max) break;
6748 }
6749 }
6750
6751 /*
6752 * Restore the tree structure
6753 */
6754 if (prev) prev->next = prev_next;
6755 if (next) next->prev = next_prev;
6756 parent->children = parent_childs;
6757 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006758
6759 /*
6760 * Free up the dummy node
6761 */
6762 test_node->name = name;
6763 xmlFreeNode(test_node);
6764
Owen Taylor3473f882001-02-23 17:55:21 +00006765 return(nb_valid_elements);
6766}
Daniel Veillard4432df22003-09-28 18:58:27 +00006767#endif /* LIBXML_VALID_ENABLED */
6768