blob: 685ce6ff462c349a91244f50ff043469dd8abd59 [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) {
223 channel = ctxt->error;
224 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/**
1210 * xmlCreateElementTable:
1211 *
1212 * create and initialize an empty element hash table.
1213 *
1214 * Returns the xmlElementTablePtr just created or NULL in case of error.
1215 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001216static xmlElementTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001217xmlCreateElementTable(void) {
1218 return(xmlHashCreate(0));
1219}
1220
1221/**
1222 * xmlFreeElement:
1223 * @elem: An element
1224 *
1225 * Deallocate the memory used by an element definition
1226 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001227static void
Owen Taylor3473f882001-02-23 17:55:21 +00001228xmlFreeElement(xmlElementPtr elem) {
1229 if (elem == NULL) return;
1230 xmlUnlinkNode((xmlNodePtr) elem);
1231 xmlFreeElementContent(elem->content);
1232 if (elem->name != NULL)
1233 xmlFree((xmlChar *) elem->name);
1234 if (elem->prefix != NULL)
1235 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001236#ifdef LIBXML_REGEXP_ENABLED
1237 if (elem->contModel != NULL)
1238 xmlRegFreeRegexp(elem->contModel);
1239#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001240 xmlFree(elem);
1241}
1242
1243
1244/**
1245 * xmlAddElementDecl:
1246 * @ctxt: the validation context
1247 * @dtd: pointer to the DTD
1248 * @name: the entity name
1249 * @type: the element type
1250 * @content: the element content tree or NULL
1251 *
1252 * Register a new element declaration
1253 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001254 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001255 */
1256xmlElementPtr
William M. Brackedb65a72004-02-06 07:36:04 +00001257xmlAddElementDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001258 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001259 xmlElementTypeVal type,
1260 xmlElementContentPtr content) {
1261 xmlElementPtr ret;
1262 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001263 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001264 xmlChar *ns, *uqname;
1265
1266 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001267 return(NULL);
1268 }
1269 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001270 return(NULL);
1271 }
1272 switch (type) {
1273 case XML_ELEMENT_TYPE_EMPTY:
1274 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001275 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1276 "xmlAddElementDecl: content != NULL for EMPTY\n",
1277 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001278 return(NULL);
1279 }
1280 break;
1281 case XML_ELEMENT_TYPE_ANY:
1282 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001283 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1284 "xmlAddElementDecl: content != NULL for ANY\n",
1285 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001286 return(NULL);
1287 }
1288 break;
1289 case XML_ELEMENT_TYPE_MIXED:
1290 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001291 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1292 "xmlAddElementDecl: content == NULL for MIXED\n",
1293 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001294 return(NULL);
1295 }
1296 break;
1297 case XML_ELEMENT_TYPE_ELEMENT:
1298 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001299 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1300 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1301 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001302 return(NULL);
1303 }
1304 break;
1305 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001306 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1307 "Internal: ELEMENT decl corrupted invalid type\n",
1308 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001309 return(NULL);
1310 }
1311
1312 /*
1313 * check if name is a QName
1314 */
1315 uqname = xmlSplitQName2(name, &ns);
1316 if (uqname != NULL)
1317 name = uqname;
1318
1319 /*
1320 * Create the Element table if needed.
1321 */
1322 table = (xmlElementTablePtr) dtd->elements;
1323 if (table == NULL) {
1324 table = xmlCreateElementTable();
1325 dtd->elements = (void *) table;
1326 }
1327 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001328 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001329 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001330 if (uqname != NULL)
1331 xmlFree(uqname);
1332 if (ns != NULL)
1333 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001334 return(NULL);
1335 }
1336
Daniel Veillarda10efa82001-04-18 13:09:01 +00001337 /*
1338 * lookup old attributes inserted on an undefined element in the
1339 * internal subset.
1340 */
1341 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1342 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1343 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1344 oldAttributes = ret->attributes;
1345 ret->attributes = NULL;
1346 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1347 xmlFreeElement(ret);
1348 }
Owen Taylor3473f882001-02-23 17:55:21 +00001349 }
Owen Taylor3473f882001-02-23 17:55:21 +00001350
1351 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001352 * The element may already be present if one of its attribute
1353 * was registered first
1354 */
1355 ret = xmlHashLookup2(table, name, ns);
1356 if (ret != NULL) {
1357 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001358#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001359 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001360 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001361 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001362 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1363 "Redefinition of element %s\n",
1364 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001365#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001366 if (uqname != NULL)
1367 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001368 if (ns != NULL)
1369 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001370 return(NULL);
1371 }
1372 } else {
1373 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1374 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001375 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001376 if (uqname != NULL)
1377 xmlFree(uqname);
1378 if (ns != NULL)
1379 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001380 return(NULL);
1381 }
1382 memset(ret, 0, sizeof(xmlElement));
1383 ret->type = XML_ELEMENT_DECL;
1384
1385 /*
1386 * fill the structure.
1387 */
1388 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001389 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001390 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001391 if (uqname != NULL)
1392 xmlFree(uqname);
1393 if (ns != NULL)
1394 xmlFree(ns);
1395 xmlFree(ret);
1396 return(NULL);
1397 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001398 ret->prefix = ns;
1399
1400 /*
1401 * Validity Check:
1402 * Insertion must not fail
1403 */
1404 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001405#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001406 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001407 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001408 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001409 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1410 "Redefinition of element %s\n",
1411 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001412#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001413 xmlFreeElement(ret);
1414 if (uqname != NULL)
1415 xmlFree(uqname);
1416 return(NULL);
1417 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001418 /*
1419 * For new element, may have attributes from earlier
1420 * definition in internal subset
1421 */
1422 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001423 }
1424
1425 /*
1426 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001427 */
1428 ret->etype = type;
Owen Taylor3473f882001-02-23 17:55:21 +00001429 ret->content = xmlCopyElementContent(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001430
1431 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001432 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001433 */
1434 ret->parent = dtd;
1435 ret->doc = dtd->doc;
1436 if (dtd->last == NULL) {
1437 dtd->children = dtd->last = (xmlNodePtr) ret;
1438 } else {
1439 dtd->last->next = (xmlNodePtr) ret;
1440 ret->prev = dtd->last;
1441 dtd->last = (xmlNodePtr) ret;
1442 }
1443 if (uqname != NULL)
1444 xmlFree(uqname);
1445 return(ret);
1446}
1447
1448/**
1449 * xmlFreeElementTable:
1450 * @table: An element table
1451 *
1452 * Deallocate the memory used by an element hash table.
1453 */
1454void
1455xmlFreeElementTable(xmlElementTablePtr table) {
1456 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1457}
1458
Daniel Veillard652327a2003-09-29 18:02:38 +00001459#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001460/**
1461 * xmlCopyElement:
1462 * @elem: An element
1463 *
1464 * Build a copy of an element.
1465 *
1466 * Returns the new xmlElementPtr or NULL in case of error.
1467 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001468static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001469xmlCopyElement(xmlElementPtr elem) {
1470 xmlElementPtr cur;
1471
1472 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1473 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001474 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001475 return(NULL);
1476 }
1477 memset(cur, 0, sizeof(xmlElement));
1478 cur->type = XML_ELEMENT_DECL;
1479 cur->etype = elem->etype;
1480 if (elem->name != NULL)
1481 cur->name = xmlStrdup(elem->name);
1482 else
1483 cur->name = NULL;
1484 if (elem->prefix != NULL)
1485 cur->prefix = xmlStrdup(elem->prefix);
1486 else
1487 cur->prefix = NULL;
1488 cur->content = xmlCopyElementContent(elem->content);
1489 /* TODO : rebuild the attribute list on the copy */
1490 cur->attributes = NULL;
1491 return(cur);
1492}
1493
1494/**
1495 * xmlCopyElementTable:
1496 * @table: An element table
1497 *
1498 * Build a copy of an element table.
1499 *
1500 * Returns the new xmlElementTablePtr or NULL in case of error.
1501 */
1502xmlElementTablePtr
1503xmlCopyElementTable(xmlElementTablePtr table) {
1504 return((xmlElementTablePtr) xmlHashCopy(table,
1505 (xmlHashCopier) xmlCopyElement));
1506}
Daniel Veillard652327a2003-09-29 18:02:38 +00001507#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001508
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001509#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001510/**
1511 * xmlDumpElementDecl:
1512 * @buf: the XML buffer output
1513 * @elem: An element table
1514 *
1515 * This will dump the content of the element declaration as an XML
1516 * DTD definition
1517 */
1518void
1519xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001520 if ((buf == NULL) || (elem == NULL))
1521 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001522 switch (elem->etype) {
1523 case XML_ELEMENT_TYPE_EMPTY:
1524 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001525 if (elem->prefix != NULL) {
1526 xmlBufferWriteCHAR(buf, elem->prefix);
1527 xmlBufferWriteChar(buf, ":");
1528 }
Owen Taylor3473f882001-02-23 17:55:21 +00001529 xmlBufferWriteCHAR(buf, elem->name);
1530 xmlBufferWriteChar(buf, " EMPTY>\n");
1531 break;
1532 case XML_ELEMENT_TYPE_ANY:
1533 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001534 if (elem->prefix != NULL) {
1535 xmlBufferWriteCHAR(buf, elem->prefix);
1536 xmlBufferWriteChar(buf, ":");
1537 }
Owen Taylor3473f882001-02-23 17:55:21 +00001538 xmlBufferWriteCHAR(buf, elem->name);
1539 xmlBufferWriteChar(buf, " ANY>\n");
1540 break;
1541 case XML_ELEMENT_TYPE_MIXED:
1542 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001543 if (elem->prefix != NULL) {
1544 xmlBufferWriteCHAR(buf, elem->prefix);
1545 xmlBufferWriteChar(buf, ":");
1546 }
Owen Taylor3473f882001-02-23 17:55:21 +00001547 xmlBufferWriteCHAR(buf, elem->name);
1548 xmlBufferWriteChar(buf, " ");
1549 xmlDumpElementContent(buf, elem->content, 1);
1550 xmlBufferWriteChar(buf, ">\n");
1551 break;
1552 case XML_ELEMENT_TYPE_ELEMENT:
1553 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001554 if (elem->prefix != NULL) {
1555 xmlBufferWriteCHAR(buf, elem->prefix);
1556 xmlBufferWriteChar(buf, ":");
1557 }
Owen Taylor3473f882001-02-23 17:55:21 +00001558 xmlBufferWriteCHAR(buf, elem->name);
1559 xmlBufferWriteChar(buf, " ");
1560 xmlDumpElementContent(buf, elem->content, 1);
1561 xmlBufferWriteChar(buf, ">\n");
1562 break;
1563 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001564 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1565 "Internal: ELEMENT struct corrupted invalid type\n",
1566 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001567 }
1568}
1569
1570/**
William M. Brack9e660592003-10-20 14:56:06 +00001571 * xmlDumpElementDeclScan:
1572 * @elem: An element table
1573 * @buf: the XML buffer output
1574 *
1575 * This routine is used by the hash scan function. It just reverses
1576 * the arguments.
1577 */
1578static void
1579xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1580 xmlDumpElementDecl(buf, elem);
1581}
1582
1583/**
Owen Taylor3473f882001-02-23 17:55:21 +00001584 * xmlDumpElementTable:
1585 * @buf: the XML buffer output
1586 * @table: An element table
1587 *
1588 * This will dump the content of the element table as an XML DTD definition
1589 */
1590void
1591xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001592 if ((buf == NULL) || (table == NULL))
1593 return;
William M. Brack9e660592003-10-20 14:56:06 +00001594 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001595}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001596#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001597
1598/**
1599 * xmlCreateEnumeration:
1600 * @name: the enumeration name or NULL
1601 *
1602 * create and initialize an enumeration attribute node.
1603 *
1604 * Returns the xmlEnumerationPtr just created or NULL in case
1605 * of error.
1606 */
1607xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001608xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001609 xmlEnumerationPtr ret;
1610
1611 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1612 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001613 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001614 return(NULL);
1615 }
1616 memset(ret, 0, sizeof(xmlEnumeration));
1617
1618 if (name != NULL)
1619 ret->name = xmlStrdup(name);
1620 return(ret);
1621}
1622
1623/**
1624 * xmlFreeEnumeration:
1625 * @cur: the tree to free.
1626 *
1627 * free an enumeration attribute node (recursive).
1628 */
1629void
1630xmlFreeEnumeration(xmlEnumerationPtr cur) {
1631 if (cur == NULL) return;
1632
1633 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1634
1635 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001636 xmlFree(cur);
1637}
1638
Daniel Veillard652327a2003-09-29 18:02:38 +00001639#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001640/**
1641 * xmlCopyEnumeration:
1642 * @cur: the tree to copy.
1643 *
1644 * Copy an enumeration attribute node (recursive).
1645 *
1646 * Returns the xmlEnumerationPtr just created or NULL in case
1647 * of error.
1648 */
1649xmlEnumerationPtr
1650xmlCopyEnumeration(xmlEnumerationPtr cur) {
1651 xmlEnumerationPtr ret;
1652
1653 if (cur == NULL) return(NULL);
1654 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1655
1656 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1657 else ret->next = NULL;
1658
1659 return(ret);
1660}
Daniel Veillard652327a2003-09-29 18:02:38 +00001661#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001662
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001663#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001664/**
1665 * xmlDumpEnumeration:
1666 * @buf: the XML buffer output
1667 * @enum: An enumeration
1668 *
1669 * This will dump the content of the enumeration
1670 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001671static void
Owen Taylor3473f882001-02-23 17:55:21 +00001672xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001673 if ((buf == NULL) || (cur == NULL))
1674 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001675
1676 xmlBufferWriteCHAR(buf, cur->name);
1677 if (cur->next == NULL)
1678 xmlBufferWriteChar(buf, ")");
1679 else {
1680 xmlBufferWriteChar(buf, " | ");
1681 xmlDumpEnumeration(buf, cur->next);
1682 }
1683}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001684#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001685
1686/**
1687 * xmlCreateAttributeTable:
1688 *
1689 * create and initialize an empty attribute hash table.
1690 *
1691 * Returns the xmlAttributeTablePtr just created or NULL in case
1692 * of error.
1693 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001694static xmlAttributeTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001695xmlCreateAttributeTable(void) {
1696 return(xmlHashCreate(0));
1697}
1698
Daniel Veillard4432df22003-09-28 18:58:27 +00001699#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001700/**
1701 * xmlScanAttributeDeclCallback:
1702 * @attr: the attribute decl
1703 * @list: the list to update
1704 *
1705 * Callback called by xmlScanAttributeDecl when a new attribute
1706 * has to be entered in the list.
1707 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001708static void
Owen Taylor3473f882001-02-23 17:55:21 +00001709xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001710 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001711 attr->nexth = *list;
1712 *list = attr;
1713}
1714
1715/**
1716 * xmlScanAttributeDecl:
1717 * @dtd: pointer to the DTD
1718 * @elem: the element name
1719 *
1720 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001721 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001722 *
1723 * Returns the pointer to the first attribute decl in the chain,
1724 * possibly NULL.
1725 */
1726xmlAttributePtr
1727xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1728 xmlAttributePtr ret = NULL;
1729 xmlAttributeTablePtr table;
1730
1731 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001732 return(NULL);
1733 }
1734 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001735 return(NULL);
1736 }
1737 table = (xmlAttributeTablePtr) dtd->attributes;
1738 if (table == NULL)
1739 return(NULL);
1740
1741 /* WRONG !!! */
1742 xmlHashScan3(table, NULL, NULL, elem,
1743 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1744 return(ret);
1745}
1746
1747/**
1748 * xmlScanIDAttributeDecl:
1749 * @ctxt: the validation context
1750 * @elem: the element name
1751 *
1752 * Verify that the element don't have too many ID attributes
1753 * declared.
1754 *
1755 * Returns the number of ID attributes found.
1756 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001757static int
Owen Taylor3473f882001-02-23 17:55:21 +00001758xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1759 xmlAttributePtr cur;
1760 int ret = 0;
1761
1762 if (elem == NULL) return(0);
1763 cur = elem->attributes;
1764 while (cur != NULL) {
1765 if (cur->atype == XML_ATTRIBUTE_ID) {
1766 ret ++;
1767 if (ret > 1)
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001768 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001769 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001770 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001771 }
1772 cur = cur->nexth;
1773 }
1774 return(ret);
1775}
Daniel Veillard4432df22003-09-28 18:58:27 +00001776#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001777
1778/**
1779 * xmlFreeAttribute:
1780 * @elem: An attribute
1781 *
1782 * Deallocate the memory used by an attribute definition
1783 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001784static void
Owen Taylor3473f882001-02-23 17:55:21 +00001785xmlFreeAttribute(xmlAttributePtr attr) {
1786 if (attr == NULL) return;
1787 xmlUnlinkNode((xmlNodePtr) attr);
1788 if (attr->tree != NULL)
1789 xmlFreeEnumeration(attr->tree);
1790 if (attr->elem != NULL)
1791 xmlFree((xmlChar *) attr->elem);
1792 if (attr->name != NULL)
1793 xmlFree((xmlChar *) attr->name);
1794 if (attr->defaultValue != NULL)
1795 xmlFree((xmlChar *) attr->defaultValue);
1796 if (attr->prefix != NULL)
1797 xmlFree((xmlChar *) attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001798 xmlFree(attr);
1799}
1800
1801
1802/**
1803 * xmlAddAttributeDecl:
1804 * @ctxt: the validation context
1805 * @dtd: pointer to the DTD
1806 * @elem: the element name
1807 * @name: the attribute name
1808 * @ns: the attribute namespace prefix
1809 * @type: the attribute type
1810 * @def: the attribute default type
1811 * @defaultValue: the attribute default value
1812 * @tree: if it's an enumeration, the associated list
1813 *
1814 * Register a new attribute declaration
1815 * Note that @tree becomes the ownership of the DTD
1816 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001817 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001818 */
1819xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001820xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001821 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001822 const xmlChar *name, const xmlChar *ns,
1823 xmlAttributeType type, xmlAttributeDefault def,
1824 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1825 xmlAttributePtr ret;
1826 xmlAttributeTablePtr table;
1827 xmlElementPtr elemDef;
1828
1829 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001830 xmlFreeEnumeration(tree);
1831 return(NULL);
1832 }
1833 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001834 xmlFreeEnumeration(tree);
1835 return(NULL);
1836 }
1837 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001838 xmlFreeEnumeration(tree);
1839 return(NULL);
1840 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001841
Daniel Veillard4432df22003-09-28 18:58:27 +00001842#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001843 /*
1844 * Check the type and possibly the default value.
1845 */
1846 switch (type) {
1847 case XML_ATTRIBUTE_CDATA:
1848 break;
1849 case XML_ATTRIBUTE_ID:
1850 break;
1851 case XML_ATTRIBUTE_IDREF:
1852 break;
1853 case XML_ATTRIBUTE_IDREFS:
1854 break;
1855 case XML_ATTRIBUTE_ENTITY:
1856 break;
1857 case XML_ATTRIBUTE_ENTITIES:
1858 break;
1859 case XML_ATTRIBUTE_NMTOKEN:
1860 break;
1861 case XML_ATTRIBUTE_NMTOKENS:
1862 break;
1863 case XML_ATTRIBUTE_ENUMERATION:
1864 break;
1865 case XML_ATTRIBUTE_NOTATION:
1866 break;
1867 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001868 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1869 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1870 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001871 xmlFreeEnumeration(tree);
1872 return(NULL);
1873 }
1874 if ((defaultValue != NULL) &&
1875 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001876 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1877 "Attribute %s of %s: invalid default value\n",
1878 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00001879 defaultValue = NULL;
Daniel Veillardd01fd3e2002-02-18 22:27:47 +00001880 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001881 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001882#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001883
1884 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001885 * Check first that an attribute defined in the external subset wasn't
1886 * already defined in the internal subset
1887 */
1888 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1889 (dtd->doc->intSubset != NULL) &&
1890 (dtd->doc->intSubset->attributes != NULL)) {
1891 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1892 if (ret != NULL)
1893 return(NULL);
1894 }
1895
1896 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001897 * Create the Attribute table if needed.
1898 */
1899 table = (xmlAttributeTablePtr) dtd->attributes;
1900 if (table == NULL) {
1901 table = xmlCreateAttributeTable();
1902 dtd->attributes = (void *) table;
1903 }
1904 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001905 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001906 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001907 return(NULL);
1908 }
1909
1910
1911 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1912 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001913 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001914 return(NULL);
1915 }
1916 memset(ret, 0, sizeof(xmlAttribute));
1917 ret->type = XML_ATTRIBUTE_DECL;
1918
1919 /*
1920 * fill the structure.
1921 */
1922 ret->atype = type;
1923 ret->name = xmlStrdup(name);
1924 ret->prefix = xmlStrdup(ns);
1925 ret->elem = xmlStrdup(elem);
1926 ret->def = def;
1927 ret->tree = tree;
1928 if (defaultValue != NULL)
1929 ret->defaultValue = xmlStrdup(defaultValue);
1930
1931 /*
1932 * Validity Check:
1933 * Search the DTD for previous declarations of the ATTLIST
1934 */
1935 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001936#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001937 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001938 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00001939 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001940 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00001941 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001942 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001943#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001944 xmlFreeAttribute(ret);
1945 return(NULL);
1946 }
1947
1948 /*
1949 * Validity Check:
1950 * Multiple ID per element
1951 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001952 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001953 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00001954
Daniel Veillard4432df22003-09-28 18:58:27 +00001955#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001956 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00001957 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001958 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00001959 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001960 elem, name, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00001961 ctxt->valid = 0;
1962 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001963#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00001964
Daniel Veillard48da9102001-08-07 01:10:10 +00001965 /*
1966 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001967 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00001968 */
1969 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1970 ((ret->prefix != NULL &&
1971 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1972 ret->nexth = elemDef->attributes;
1973 elemDef->attributes = ret;
1974 } else {
1975 xmlAttributePtr tmp = elemDef->attributes;
1976
1977 while ((tmp != NULL) &&
1978 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1979 ((ret->prefix != NULL &&
1980 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1981 if (tmp->nexth == NULL)
1982 break;
1983 tmp = tmp->nexth;
1984 }
1985 if (tmp != NULL) {
1986 ret->nexth = tmp->nexth;
1987 tmp->nexth = ret;
1988 } else {
1989 ret->nexth = elemDef->attributes;
1990 elemDef->attributes = ret;
1991 }
1992 }
Owen Taylor3473f882001-02-23 17:55:21 +00001993 }
1994
1995 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001996 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001997 */
1998 ret->parent = dtd;
1999 ret->doc = dtd->doc;
2000 if (dtd->last == NULL) {
2001 dtd->children = dtd->last = (xmlNodePtr) ret;
2002 } else {
2003 dtd->last->next = (xmlNodePtr) ret;
2004 ret->prev = dtd->last;
2005 dtd->last = (xmlNodePtr) ret;
2006 }
2007 return(ret);
2008}
2009
2010/**
2011 * xmlFreeAttributeTable:
2012 * @table: An attribute table
2013 *
2014 * Deallocate the memory used by an entities hash table.
2015 */
2016void
2017xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2018 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
2019}
2020
Daniel Veillard652327a2003-09-29 18:02:38 +00002021#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002022/**
2023 * xmlCopyAttribute:
2024 * @attr: An attribute
2025 *
2026 * Build a copy of an attribute.
2027 *
2028 * Returns the new xmlAttributePtr or NULL in case of error.
2029 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002030static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002031xmlCopyAttribute(xmlAttributePtr attr) {
2032 xmlAttributePtr cur;
2033
2034 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2035 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002036 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002037 return(NULL);
2038 }
2039 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00002040 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00002041 cur->atype = attr->atype;
2042 cur->def = attr->def;
2043 cur->tree = xmlCopyEnumeration(attr->tree);
2044 if (attr->elem != NULL)
2045 cur->elem = xmlStrdup(attr->elem);
2046 if (attr->name != NULL)
2047 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002048 if (attr->prefix != NULL)
2049 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002050 if (attr->defaultValue != NULL)
2051 cur->defaultValue = xmlStrdup(attr->defaultValue);
2052 return(cur);
2053}
2054
2055/**
2056 * xmlCopyAttributeTable:
2057 * @table: An attribute table
2058 *
2059 * Build a copy of an attribute table.
2060 *
2061 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2062 */
2063xmlAttributeTablePtr
2064xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2065 return((xmlAttributeTablePtr) xmlHashCopy(table,
2066 (xmlHashCopier) xmlCopyAttribute));
2067}
Daniel Veillard652327a2003-09-29 18:02:38 +00002068#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002069
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002070#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002071/**
2072 * xmlDumpAttributeDecl:
2073 * @buf: the XML buffer output
2074 * @attr: An attribute declaration
2075 *
2076 * This will dump the content of the attribute declaration as an XML
2077 * DTD definition
2078 */
2079void
2080xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002081 if ((buf == NULL) || (attr == NULL))
2082 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002083 xmlBufferWriteChar(buf, "<!ATTLIST ");
2084 xmlBufferWriteCHAR(buf, attr->elem);
2085 xmlBufferWriteChar(buf, " ");
2086 if (attr->prefix != NULL) {
2087 xmlBufferWriteCHAR(buf, attr->prefix);
2088 xmlBufferWriteChar(buf, ":");
2089 }
2090 xmlBufferWriteCHAR(buf, attr->name);
2091 switch (attr->atype) {
2092 case XML_ATTRIBUTE_CDATA:
2093 xmlBufferWriteChar(buf, " CDATA");
2094 break;
2095 case XML_ATTRIBUTE_ID:
2096 xmlBufferWriteChar(buf, " ID");
2097 break;
2098 case XML_ATTRIBUTE_IDREF:
2099 xmlBufferWriteChar(buf, " IDREF");
2100 break;
2101 case XML_ATTRIBUTE_IDREFS:
2102 xmlBufferWriteChar(buf, " IDREFS");
2103 break;
2104 case XML_ATTRIBUTE_ENTITY:
2105 xmlBufferWriteChar(buf, " ENTITY");
2106 break;
2107 case XML_ATTRIBUTE_ENTITIES:
2108 xmlBufferWriteChar(buf, " ENTITIES");
2109 break;
2110 case XML_ATTRIBUTE_NMTOKEN:
2111 xmlBufferWriteChar(buf, " NMTOKEN");
2112 break;
2113 case XML_ATTRIBUTE_NMTOKENS:
2114 xmlBufferWriteChar(buf, " NMTOKENS");
2115 break;
2116 case XML_ATTRIBUTE_ENUMERATION:
2117 xmlBufferWriteChar(buf, " (");
2118 xmlDumpEnumeration(buf, attr->tree);
2119 break;
2120 case XML_ATTRIBUTE_NOTATION:
2121 xmlBufferWriteChar(buf, " NOTATION (");
2122 xmlDumpEnumeration(buf, attr->tree);
2123 break;
2124 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002125 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2126 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2127 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002128 }
2129 switch (attr->def) {
2130 case XML_ATTRIBUTE_NONE:
2131 break;
2132 case XML_ATTRIBUTE_REQUIRED:
2133 xmlBufferWriteChar(buf, " #REQUIRED");
2134 break;
2135 case XML_ATTRIBUTE_IMPLIED:
2136 xmlBufferWriteChar(buf, " #IMPLIED");
2137 break;
2138 case XML_ATTRIBUTE_FIXED:
2139 xmlBufferWriteChar(buf, " #FIXED");
2140 break;
2141 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002142 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2143 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2144 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002145 }
2146 if (attr->defaultValue != NULL) {
2147 xmlBufferWriteChar(buf, " ");
2148 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2149 }
2150 xmlBufferWriteChar(buf, ">\n");
2151}
2152
2153/**
William M. Brack9e660592003-10-20 14:56:06 +00002154 * xmlDumpAttributeDeclScan:
2155 * @attr: An attribute declaration
2156 * @buf: the XML buffer output
2157 *
2158 * This is used with the hash scan function - just reverses arguments
2159 */
2160static void
2161xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2162 xmlDumpAttributeDecl(buf, attr);
2163}
2164
2165/**
Owen Taylor3473f882001-02-23 17:55:21 +00002166 * xmlDumpAttributeTable:
2167 * @buf: the XML buffer output
2168 * @table: An attribute table
2169 *
2170 * This will dump the content of the attribute table as an XML DTD definition
2171 */
2172void
2173xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002174 if ((buf == NULL) || (table == NULL))
2175 return;
William M. Brack9e660592003-10-20 14:56:06 +00002176 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002177}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002178#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002179
2180/************************************************************************
2181 * *
2182 * NOTATIONs *
2183 * *
2184 ************************************************************************/
2185/**
2186 * xmlCreateNotationTable:
2187 *
2188 * create and initialize an empty notation hash table.
2189 *
2190 * Returns the xmlNotationTablePtr just created or NULL in case
2191 * of error.
2192 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002193static xmlNotationTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002194xmlCreateNotationTable(void) {
2195 return(xmlHashCreate(0));
2196}
2197
2198/**
2199 * xmlFreeNotation:
2200 * @not: A notation
2201 *
2202 * Deallocate the memory used by an notation definition
2203 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002204static void
Owen Taylor3473f882001-02-23 17:55:21 +00002205xmlFreeNotation(xmlNotationPtr nota) {
2206 if (nota == NULL) return;
2207 if (nota->name != NULL)
2208 xmlFree((xmlChar *) nota->name);
2209 if (nota->PublicID != NULL)
2210 xmlFree((xmlChar *) nota->PublicID);
2211 if (nota->SystemID != NULL)
2212 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002213 xmlFree(nota);
2214}
2215
2216
2217/**
2218 * xmlAddNotationDecl:
2219 * @dtd: pointer to the DTD
2220 * @ctxt: the validation context
2221 * @name: the entity name
2222 * @PublicID: the public identifier or NULL
2223 * @SystemID: the system identifier or NULL
2224 *
2225 * Register a new notation declaration
2226 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002227 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002228 */
2229xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002230xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002231 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002232 const xmlChar *PublicID, const xmlChar *SystemID) {
2233 xmlNotationPtr ret;
2234 xmlNotationTablePtr table;
2235
2236 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002237 return(NULL);
2238 }
2239 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002240 return(NULL);
2241 }
2242 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002243 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002244 }
2245
2246 /*
2247 * Create the Notation table if needed.
2248 */
2249 table = (xmlNotationTablePtr) dtd->notations;
2250 if (table == NULL)
2251 dtd->notations = table = xmlCreateNotationTable();
2252 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002253 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002254 "xmlAddNotationDecl: Table creation failed!\n");
2255 return(NULL);
2256 }
2257
2258 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2259 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002260 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002261 return(NULL);
2262 }
2263 memset(ret, 0, sizeof(xmlNotation));
2264
2265 /*
2266 * fill the structure.
2267 */
2268 ret->name = xmlStrdup(name);
2269 if (SystemID != NULL)
2270 ret->SystemID = xmlStrdup(SystemID);
2271 if (PublicID != NULL)
2272 ret->PublicID = xmlStrdup(PublicID);
2273
2274 /*
2275 * Validity Check:
2276 * Check the DTD for previous declarations of the ATTLIST
2277 */
2278 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002279#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002280 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2281 "xmlAddNotationDecl: %s already defined\n",
2282 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002283#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002284 xmlFreeNotation(ret);
2285 return(NULL);
2286 }
2287 return(ret);
2288}
2289
2290/**
2291 * xmlFreeNotationTable:
2292 * @table: An notation table
2293 *
2294 * Deallocate the memory used by an entities hash table.
2295 */
2296void
2297xmlFreeNotationTable(xmlNotationTablePtr table) {
2298 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2299}
2300
Daniel Veillard652327a2003-09-29 18:02:38 +00002301#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002302/**
2303 * xmlCopyNotation:
2304 * @nota: A notation
2305 *
2306 * Build a copy of a notation.
2307 *
2308 * Returns the new xmlNotationPtr or NULL in case of error.
2309 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002310static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002311xmlCopyNotation(xmlNotationPtr nota) {
2312 xmlNotationPtr cur;
2313
2314 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2315 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002316 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002317 return(NULL);
2318 }
2319 if (nota->name != NULL)
2320 cur->name = xmlStrdup(nota->name);
2321 else
2322 cur->name = NULL;
2323 if (nota->PublicID != NULL)
2324 cur->PublicID = xmlStrdup(nota->PublicID);
2325 else
2326 cur->PublicID = NULL;
2327 if (nota->SystemID != NULL)
2328 cur->SystemID = xmlStrdup(nota->SystemID);
2329 else
2330 cur->SystemID = NULL;
2331 return(cur);
2332}
2333
2334/**
2335 * xmlCopyNotationTable:
2336 * @table: A notation table
2337 *
2338 * Build a copy of a notation table.
2339 *
2340 * Returns the new xmlNotationTablePtr or NULL in case of error.
2341 */
2342xmlNotationTablePtr
2343xmlCopyNotationTable(xmlNotationTablePtr table) {
2344 return((xmlNotationTablePtr) xmlHashCopy(table,
2345 (xmlHashCopier) xmlCopyNotation));
2346}
Daniel Veillard652327a2003-09-29 18:02:38 +00002347#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002348
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002349#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002350/**
2351 * xmlDumpNotationDecl:
2352 * @buf: the XML buffer output
2353 * @nota: A notation declaration
2354 *
2355 * This will dump the content the notation declaration as an XML DTD definition
2356 */
2357void
2358xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002359 if ((buf == NULL) || (nota == NULL))
2360 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002361 xmlBufferWriteChar(buf, "<!NOTATION ");
2362 xmlBufferWriteCHAR(buf, nota->name);
2363 if (nota->PublicID != NULL) {
2364 xmlBufferWriteChar(buf, " PUBLIC ");
2365 xmlBufferWriteQuotedString(buf, nota->PublicID);
2366 if (nota->SystemID != NULL) {
2367 xmlBufferWriteChar(buf, " ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002368 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002369 }
2370 } else {
2371 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002372 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002373 }
2374 xmlBufferWriteChar(buf, " >\n");
2375}
2376
2377/**
William M. Brack9e660592003-10-20 14:56:06 +00002378 * xmlDumpNotationDeclScan:
2379 * @nota: A notation declaration
2380 * @buf: the XML buffer output
2381 *
2382 * This is called with the hash scan function, and just reverses args
2383 */
2384static void
2385xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2386 xmlDumpNotationDecl(buf, nota);
2387}
2388
2389/**
Owen Taylor3473f882001-02-23 17:55:21 +00002390 * xmlDumpNotationTable:
2391 * @buf: the XML buffer output
2392 * @table: A notation table
2393 *
2394 * This will dump the content of the notation table as an XML DTD definition
2395 */
2396void
2397xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002398 if ((buf == NULL) || (table == NULL))
2399 return;
William M. Brack9e660592003-10-20 14:56:06 +00002400 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002401}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002402#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002403
2404/************************************************************************
2405 * *
2406 * IDs *
2407 * *
2408 ************************************************************************/
2409/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002410 * DICT_FREE:
2411 * @str: a string
2412 *
2413 * Free a string if it is not owned by the "dict" dictionnary in the
2414 * current scope
2415 */
2416#define DICT_FREE(str) \
2417 if ((str) && ((!dict) || \
2418 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2419 xmlFree((char *)(str));
2420
2421/**
Owen Taylor3473f882001-02-23 17:55:21 +00002422 * xmlCreateIDTable:
2423 *
2424 * create and initialize an empty id hash table.
2425 *
2426 * Returns the xmlIDTablePtr just created or NULL in case
2427 * of error.
2428 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002429static xmlIDTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002430xmlCreateIDTable(void) {
2431 return(xmlHashCreate(0));
2432}
2433
2434/**
2435 * xmlFreeID:
2436 * @not: A id
2437 *
2438 * Deallocate the memory used by an id definition
2439 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002440static void
Owen Taylor3473f882001-02-23 17:55:21 +00002441xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002442 xmlDictPtr dict = NULL;
2443
Owen Taylor3473f882001-02-23 17:55:21 +00002444 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002445
2446 if (id->doc != NULL)
2447 dict = id->doc->dict;
2448
Owen Taylor3473f882001-02-23 17:55:21 +00002449 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002450 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002451 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002452 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002453 xmlFree(id);
2454}
2455
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002456
Owen Taylor3473f882001-02-23 17:55:21 +00002457/**
2458 * xmlAddID:
2459 * @ctxt: the validation context
2460 * @doc: pointer to the document
2461 * @value: the value name
2462 * @attr: the attribute holding the ID
2463 *
2464 * Register a new id declaration
2465 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002466 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002467 */
2468xmlIDPtr
2469xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2470 xmlAttrPtr attr) {
2471 xmlIDPtr ret;
2472 xmlIDTablePtr table;
2473
2474 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002475 return(NULL);
2476 }
2477 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002478 return(NULL);
2479 }
2480 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002481 return(NULL);
2482 }
2483
2484 /*
2485 * Create the ID table if needed.
2486 */
2487 table = (xmlIDTablePtr) doc->ids;
2488 if (table == NULL)
2489 doc->ids = table = xmlCreateIDTable();
2490 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002491 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002492 "xmlAddID: Table creation failed!\n");
2493 return(NULL);
2494 }
2495
2496 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2497 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002498 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002499 return(NULL);
2500 }
2501
2502 /*
2503 * fill the structure.
2504 */
2505 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002506 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002507 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2508 /*
2509 * Operating in streaming mode, attr is gonna disapear
2510 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002511 if (doc->dict != NULL)
2512 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2513 else
2514 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002515 ret->attr = NULL;
2516 } else {
2517 ret->attr = attr;
2518 ret->name = NULL;
2519 }
2520 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002521
2522 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002523#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002524 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002525 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002526 */
Daniel Veillardd3669b22004-02-25 12:34:55 +00002527 if ((ctxt != NULL) && (ctxt->error != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002528 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2529 "ID %s already defined\n",
2530 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002531 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002532#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002533 xmlFreeID(ret);
2534 return(NULL);
2535 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002536 if (attr != NULL)
2537 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002538 return(ret);
2539}
2540
2541/**
2542 * xmlFreeIDTable:
2543 * @table: An id table
2544 *
2545 * Deallocate the memory used by an ID hash table.
2546 */
2547void
2548xmlFreeIDTable(xmlIDTablePtr table) {
2549 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2550}
2551
2552/**
2553 * xmlIsID:
2554 * @doc: the document
2555 * @elem: the element carrying the attribute
2556 * @attr: the attribute
2557 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002558 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002559 * then this is done if DTD loading has been requested. In the case
2560 * of HTML documents parsed with the HTML parser, then ID detection is
2561 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002562 *
2563 * Returns 0 or 1 depending on the lookup result
2564 */
2565int
2566xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2567 if (doc == NULL) return(0);
2568 if (attr == NULL) return(0);
2569 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2570 return(0);
2571 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard9ba8e382003-10-28 21:31:45 +00002572 if (((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2573 (xmlStrEqual(BAD_CAST "name", attr->name))) &&
2574 ((elem != NULL) && (!xmlStrEqual(elem->name, BAD_CAST "input"))))
Owen Taylor3473f882001-02-23 17:55:21 +00002575 return(1);
2576 return(0);
2577 } else {
2578 xmlAttributePtr attrDecl;
2579
2580 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002581 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002582 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002583 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002584
2585 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002586 if (fullname == NULL)
2587 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002588 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2589 attr->name);
2590 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2591 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2592 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002593 if ((fullname != fn) && (fullname != elem->name))
2594 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002595 } else {
2596 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2597 attr->name);
2598 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2599 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2600 attr->name);
2601 }
Owen Taylor3473f882001-02-23 17:55:21 +00002602
2603 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2604 return(1);
2605 }
2606 return(0);
2607}
2608
2609/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002610 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002611 * @doc: the document
2612 * @attr: the attribute
2613 *
2614 * Remove the given attribute from the ID table maintained internally.
2615 *
2616 * Returns -1 if the lookup failed and 0 otherwise
2617 */
2618int
2619xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002620 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002621 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002622 xmlChar *ID;
2623
2624 if (doc == NULL) return(-1);
2625 if (attr == NULL) return(-1);
2626 table = (xmlIDTablePtr) doc->ids;
2627 if (table == NULL)
2628 return(-1);
2629
2630 if (attr == NULL)
2631 return(-1);
2632 ID = xmlNodeListGetString(doc, attr->children, 1);
2633 if (ID == NULL)
2634 return(-1);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002635 id = xmlHashLookup(table, ID);
2636 if (id == NULL || id->attr != attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002637 xmlFree(ID);
2638 return(-1);
2639 }
2640 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
2641 xmlFree(ID);
2642 return(0);
2643}
2644
2645/**
2646 * xmlGetID:
2647 * @doc: pointer to the document
2648 * @ID: the ID value
2649 *
2650 * Search the attribute declaring the given ID
2651 *
2652 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2653 */
2654xmlAttrPtr
2655xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2656 xmlIDTablePtr table;
2657 xmlIDPtr id;
2658
2659 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002660 return(NULL);
2661 }
2662
2663 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002664 return(NULL);
2665 }
2666
2667 table = (xmlIDTablePtr) doc->ids;
2668 if (table == NULL)
2669 return(NULL);
2670
2671 id = xmlHashLookup(table, ID);
2672 if (id == NULL)
2673 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002674 if (id->attr == NULL) {
2675 /*
2676 * We are operating on a stream, return a well known reference
2677 * since the attribute node doesn't exist anymore
2678 */
2679 return((xmlAttrPtr) doc);
2680 }
Owen Taylor3473f882001-02-23 17:55:21 +00002681 return(id->attr);
2682}
2683
2684/************************************************************************
2685 * *
2686 * Refs *
2687 * *
2688 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002689typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002690{
2691 xmlListPtr l;
2692 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002693} xmlRemoveMemo;
2694
2695typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2696
2697typedef struct xmlValidateMemo_t
2698{
2699 xmlValidCtxtPtr ctxt;
2700 const xmlChar *name;
2701} xmlValidateMemo;
2702
2703typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002704
2705/**
2706 * xmlCreateRefTable:
2707 *
2708 * create and initialize an empty ref hash table.
2709 *
2710 * Returns the xmlRefTablePtr just created or NULL in case
2711 * of error.
2712 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002713static xmlRefTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002714xmlCreateRefTable(void) {
2715 return(xmlHashCreate(0));
2716}
2717
2718/**
2719 * xmlFreeRef:
2720 * @lk: A list link
2721 *
2722 * Deallocate the memory used by a ref definition
2723 */
2724static void
2725xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002726 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2727 if (ref == NULL) return;
2728 if (ref->value != NULL)
2729 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002730 if (ref->name != NULL)
2731 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002732 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002733}
2734
2735/**
2736 * xmlFreeRefList:
2737 * @list_ref: A list of references.
2738 *
2739 * Deallocate the memory used by a list of references
2740 */
2741static void
2742xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002743 if (list_ref == NULL) return;
2744 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002745}
2746
2747/**
2748 * xmlWalkRemoveRef:
2749 * @data: Contents of current link
2750 * @user: Value supplied by the user
2751 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002752 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002753 */
2754static int
2755xmlWalkRemoveRef(const void *data, const void *user)
2756{
Daniel Veillard37721922001-05-04 15:21:12 +00002757 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2758 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2759 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002760
Daniel Veillard37721922001-05-04 15:21:12 +00002761 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2762 xmlListRemoveFirst(ref_list, (void *)data);
2763 return 0;
2764 }
2765 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002766}
2767
2768/**
Daniel Veillard770075b2004-02-25 10:44:30 +00002769 * xmlDummyCompare
2770 * @data0: Value supplied by the user
2771 * @data1: Value supplied by the user
2772 *
2773 * Do nothing, return 0. Used to create unordered lists.
2774 */
2775static int
Daniel Veillardf54cd532004-02-25 11:52:31 +00002776xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2777 const void *data1 ATTRIBUTE_UNUSED)
Daniel Veillard770075b2004-02-25 10:44:30 +00002778{
2779 return (0);
2780}
2781
2782/**
Owen Taylor3473f882001-02-23 17:55:21 +00002783 * xmlAddRef:
2784 * @ctxt: the validation context
2785 * @doc: pointer to the document
2786 * @value: the value name
2787 * @attr: the attribute holding the Ref
2788 *
2789 * Register a new ref declaration
2790 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002791 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002792 */
2793xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002794xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002795 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002796 xmlRefPtr ret;
2797 xmlRefTablePtr table;
2798 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002799
Daniel Veillard37721922001-05-04 15:21:12 +00002800 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002801 return(NULL);
2802 }
2803 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002804 return(NULL);
2805 }
2806 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002807 return(NULL);
2808 }
Owen Taylor3473f882001-02-23 17:55:21 +00002809
Daniel Veillard37721922001-05-04 15:21:12 +00002810 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002811 * Create the Ref table if needed.
2812 */
Daniel Veillard37721922001-05-04 15:21:12 +00002813 table = (xmlRefTablePtr) doc->refs;
2814 if (table == NULL)
2815 doc->refs = table = xmlCreateRefTable();
2816 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002817 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002818 "xmlAddRef: Table creation failed!\n");
2819 return(NULL);
2820 }
Owen Taylor3473f882001-02-23 17:55:21 +00002821
Daniel Veillard37721922001-05-04 15:21:12 +00002822 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2823 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002824 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002825 return(NULL);
2826 }
Owen Taylor3473f882001-02-23 17:55:21 +00002827
Daniel Veillard37721922001-05-04 15:21:12 +00002828 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002829 * fill the structure.
2830 */
Daniel Veillard37721922001-05-04 15:21:12 +00002831 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002832 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2833 /*
2834 * Operating in streaming mode, attr is gonna disapear
2835 */
2836 ret->name = xmlStrdup(attr->name);
2837 ret->attr = NULL;
2838 } else {
2839 ret->name = NULL;
2840 ret->attr = attr;
2841 }
2842 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002843
Daniel Veillard37721922001-05-04 15:21:12 +00002844 /* To add a reference :-
2845 * References are maintained as a list of references,
2846 * Lookup the entry, if no entry create new nodelist
2847 * Add the owning node to the NodeList
2848 * Return the ref
2849 */
Owen Taylor3473f882001-02-23 17:55:21 +00002850
Daniel Veillard37721922001-05-04 15:21:12 +00002851 if (NULL == (ref_list = xmlHashLookup(table, value))) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002852 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002853 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2854 "xmlAddRef: Reference list creation failed!\n",
2855 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002856 return(NULL);
2857 }
2858 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2859 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002860 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2861 "xmlAddRef: Reference list insertion failed!\n",
2862 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002863 return(NULL);
2864 }
2865 }
Daniel Veillard965983a2004-02-17 16:30:24 +00002866/* xmlListInsert(ref_list, ret); */
2867 xmlListAppend(ref_list, ret);
Daniel Veillard37721922001-05-04 15:21:12 +00002868 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002869}
2870
2871/**
2872 * xmlFreeRefTable:
2873 * @table: An ref table
2874 *
2875 * Deallocate the memory used by an Ref hash table.
2876 */
2877void
2878xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002879 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002880}
2881
2882/**
2883 * xmlIsRef:
2884 * @doc: the document
2885 * @elem: the element carrying the attribute
2886 * @attr: the attribute
2887 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002888 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00002889 * then this is simple, otherwise we use an heuristic: name Ref (upper
2890 * or lowercase).
2891 *
2892 * Returns 0 or 1 depending on the lookup result
2893 */
2894int
2895xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00002896 if (attr == NULL)
2897 return(0);
2898 if (doc == NULL) {
2899 doc = attr->doc;
2900 if (doc == NULL) return(0);
2901 }
2902
Daniel Veillard37721922001-05-04 15:21:12 +00002903 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2904 return(0);
2905 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2906 /* TODO @@@ */
2907 return(0);
2908 } else {
2909 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00002910
Daniel Veillardce244ad2004-11-05 10:03:46 +00002911 if (elem == NULL) return(0);
Daniel Veillard37721922001-05-04 15:21:12 +00002912 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2913 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2914 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2915 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002916
Daniel Veillard37721922001-05-04 15:21:12 +00002917 if ((attrDecl != NULL) &&
2918 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2919 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2920 return(1);
2921 }
2922 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002923}
2924
2925/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002926 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00002927 * @doc: the document
2928 * @attr: the attribute
2929 *
2930 * Remove the given attribute from the Ref table maintained internally.
2931 *
2932 * Returns -1 if the lookup failed and 0 otherwise
2933 */
2934int
2935xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002936 xmlListPtr ref_list;
2937 xmlRefTablePtr table;
2938 xmlChar *ID;
2939 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00002940
Daniel Veillard37721922001-05-04 15:21:12 +00002941 if (doc == NULL) return(-1);
2942 if (attr == NULL) return(-1);
2943 table = (xmlRefTablePtr) doc->refs;
2944 if (table == NULL)
2945 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002946
Daniel Veillard37721922001-05-04 15:21:12 +00002947 if (attr == NULL)
2948 return(-1);
2949 ID = xmlNodeListGetString(doc, attr->children, 1);
2950 if (ID == NULL)
2951 return(-1);
2952 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00002953
Daniel Veillard37721922001-05-04 15:21:12 +00002954 if(ref_list == NULL) {
2955 xmlFree(ID);
2956 return (-1);
2957 }
2958 /* At this point, ref_list refers to a list of references which
2959 * have the same key as the supplied attr. Our list of references
2960 * is ordered by reference address and we don't have that information
2961 * here to use when removing. We'll have to walk the list and
2962 * check for a matching attribute, when we find one stop the walk
2963 * and remove the entry.
2964 * The list is ordered by reference, so that means we don't have the
2965 * key. Passing the list and the reference to the walker means we
2966 * will have enough data to be able to remove the entry.
2967 */
2968 target.l = ref_list;
2969 target.ap = attr;
2970
2971 /* Remove the supplied attr from our list */
2972 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00002973
Daniel Veillard37721922001-05-04 15:21:12 +00002974 /*If the list is empty then remove the list entry in the hash */
2975 if (xmlListEmpty(ref_list))
2976 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2977 xmlFreeRefList);
2978 xmlFree(ID);
2979 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002980}
2981
2982/**
2983 * xmlGetRefs:
2984 * @doc: pointer to the document
2985 * @ID: the ID value
2986 *
2987 * Find the set of references for the supplied ID.
2988 *
2989 * Returns NULL if not found, otherwise node set for the ID.
2990 */
2991xmlListPtr
2992xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00002993 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00002994
Daniel Veillard37721922001-05-04 15:21:12 +00002995 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002996 return(NULL);
2997 }
Owen Taylor3473f882001-02-23 17:55:21 +00002998
Daniel Veillard37721922001-05-04 15:21:12 +00002999 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003000 return(NULL);
3001 }
Owen Taylor3473f882001-02-23 17:55:21 +00003002
Daniel Veillard37721922001-05-04 15:21:12 +00003003 table = (xmlRefTablePtr) doc->refs;
3004 if (table == NULL)
3005 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003006
Daniel Veillard37721922001-05-04 15:21:12 +00003007 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00003008}
3009
3010/************************************************************************
3011 * *
3012 * Routines for validity checking *
3013 * *
3014 ************************************************************************/
3015
3016/**
3017 * xmlGetDtdElementDesc:
3018 * @dtd: a pointer to the DtD to search
3019 * @name: the element name
3020 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003021 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003022 *
3023 * returns the xmlElementPtr if found or NULL
3024 */
3025
3026xmlElementPtr
3027xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3028 xmlElementTablePtr table;
3029 xmlElementPtr cur;
3030 xmlChar *uqname = NULL, *prefix = NULL;
3031
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00003032 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003033 if (dtd->elements == NULL)
3034 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003035 table = (xmlElementTablePtr) dtd->elements;
3036
3037 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003038 if (uqname != NULL)
3039 name = uqname;
3040 cur = xmlHashLookup2(table, name, prefix);
3041 if (prefix != NULL) xmlFree(prefix);
3042 if (uqname != NULL) xmlFree(uqname);
3043 return(cur);
3044}
3045/**
3046 * xmlGetDtdElementDesc2:
3047 * @dtd: a pointer to the DtD to search
3048 * @name: the element name
3049 * @create: create an empty description if not found
3050 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003051 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00003052 *
3053 * returns the xmlElementPtr if found or NULL
3054 */
3055
Daniel Veillard86fd5a72001-12-13 14:55:21 +00003056static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00003057xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3058 xmlElementTablePtr table;
3059 xmlElementPtr cur;
3060 xmlChar *uqname = NULL, *prefix = NULL;
3061
3062 if (dtd == NULL) return(NULL);
3063 if (dtd->elements == NULL) {
3064 if (!create)
3065 return(NULL);
3066 /*
3067 * Create the Element table if needed.
3068 */
3069 table = (xmlElementTablePtr) dtd->elements;
3070 if (table == NULL) {
3071 table = xmlCreateElementTable();
3072 dtd->elements = (void *) table;
3073 }
3074 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003075 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003076 return(NULL);
3077 }
3078 }
3079 table = (xmlElementTablePtr) dtd->elements;
3080
3081 uqname = xmlSplitQName2(name, &prefix);
3082 if (uqname != NULL)
3083 name = uqname;
3084 cur = xmlHashLookup2(table, name, prefix);
3085 if ((cur == NULL) && (create)) {
3086 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3087 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003088 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003089 return(NULL);
3090 }
3091 memset(cur, 0, sizeof(xmlElement));
3092 cur->type = XML_ELEMENT_DECL;
3093
3094 /*
3095 * fill the structure.
3096 */
3097 cur->name = xmlStrdup(name);
3098 cur->prefix = xmlStrdup(prefix);
3099 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3100
3101 xmlHashAddEntry2(table, name, prefix, cur);
3102 }
3103 if (prefix != NULL) xmlFree(prefix);
3104 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003105 return(cur);
3106}
3107
3108/**
3109 * xmlGetDtdQElementDesc:
3110 * @dtd: a pointer to the DtD to search
3111 * @name: the element name
3112 * @prefix: the element namespace prefix
3113 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003114 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003115 *
3116 * returns the xmlElementPtr if found or NULL
3117 */
3118
Daniel Veillard48da9102001-08-07 01:10:10 +00003119xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003120xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3121 const xmlChar *prefix) {
3122 xmlElementTablePtr table;
3123
3124 if (dtd == NULL) return(NULL);
3125 if (dtd->elements == NULL) return(NULL);
3126 table = (xmlElementTablePtr) dtd->elements;
3127
3128 return(xmlHashLookup2(table, name, prefix));
3129}
3130
3131/**
3132 * xmlGetDtdAttrDesc:
3133 * @dtd: a pointer to the DtD to search
3134 * @elem: the element name
3135 * @name: the attribute name
3136 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003137 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003138 * this element.
3139 *
3140 * returns the xmlAttributePtr if found or NULL
3141 */
3142
3143xmlAttributePtr
3144xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3145 xmlAttributeTablePtr table;
3146 xmlAttributePtr cur;
3147 xmlChar *uqname = NULL, *prefix = NULL;
3148
3149 if (dtd == NULL) return(NULL);
3150 if (dtd->attributes == NULL) return(NULL);
3151
3152 table = (xmlAttributeTablePtr) dtd->attributes;
3153 if (table == NULL)
3154 return(NULL);
3155
3156 uqname = xmlSplitQName2(name, &prefix);
3157
3158 if (uqname != NULL) {
3159 cur = xmlHashLookup3(table, uqname, prefix, elem);
3160 if (prefix != NULL) xmlFree(prefix);
3161 if (uqname != NULL) xmlFree(uqname);
3162 } else
3163 cur = xmlHashLookup3(table, name, NULL, elem);
3164 return(cur);
3165}
3166
3167/**
3168 * xmlGetDtdQAttrDesc:
3169 * @dtd: a pointer to the DtD to search
3170 * @elem: the element name
3171 * @name: the attribute name
3172 * @prefix: the attribute namespace prefix
3173 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003174 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003175 * this element.
3176 *
3177 * returns the xmlAttributePtr if found or NULL
3178 */
3179
Daniel Veillard48da9102001-08-07 01:10:10 +00003180xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003181xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3182 const xmlChar *prefix) {
3183 xmlAttributeTablePtr table;
3184
3185 if (dtd == NULL) return(NULL);
3186 if (dtd->attributes == NULL) return(NULL);
3187 table = (xmlAttributeTablePtr) dtd->attributes;
3188
3189 return(xmlHashLookup3(table, name, prefix, elem));
3190}
3191
3192/**
3193 * xmlGetDtdNotationDesc:
3194 * @dtd: a pointer to the DtD to search
3195 * @name: the notation name
3196 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003197 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003198 *
3199 * returns the xmlNotationPtr if found or NULL
3200 */
3201
3202xmlNotationPtr
3203xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3204 xmlNotationTablePtr table;
3205
3206 if (dtd == NULL) return(NULL);
3207 if (dtd->notations == NULL) return(NULL);
3208 table = (xmlNotationTablePtr) dtd->notations;
3209
3210 return(xmlHashLookup(table, name));
3211}
3212
Daniel Veillardf54cd532004-02-25 11:52:31 +00003213#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003214/**
3215 * xmlValidateNotationUse:
3216 * @ctxt: the validation context
3217 * @doc: the document
3218 * @notationName: the notation name to check
3219 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003220 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003221 * - [ VC: Notation Declared ]
3222 *
3223 * returns 1 if valid or 0 otherwise
3224 */
3225
3226int
3227xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3228 const xmlChar *notationName) {
3229 xmlNotationPtr notaDecl;
3230 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3231
3232 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3233 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3234 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3235
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003236 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003237 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3238 "NOTATION %s is not declared\n",
3239 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003240 return(0);
3241 }
3242 return(1);
3243}
Daniel Veillardf54cd532004-02-25 11:52:31 +00003244#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003245
3246/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003247 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003248 * @doc: the document
3249 * @name: the element name
3250 *
3251 * Search in the DtDs whether an element accept Mixed content (or ANY)
3252 * basically if it is supposed to accept text childs
3253 *
3254 * returns 0 if no, 1 if yes, and -1 if no element description is available
3255 */
3256
3257int
3258xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3259 xmlElementPtr elemDecl;
3260
3261 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3262
3263 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3264 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3265 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3266 if (elemDecl == NULL) return(-1);
3267 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003268 case XML_ELEMENT_TYPE_UNDEFINED:
3269 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003270 case XML_ELEMENT_TYPE_ELEMENT:
3271 return(0);
3272 case XML_ELEMENT_TYPE_EMPTY:
3273 /*
3274 * return 1 for EMPTY since we want VC error to pop up
3275 * on <empty> </empty> for example
3276 */
3277 case XML_ELEMENT_TYPE_ANY:
3278 case XML_ELEMENT_TYPE_MIXED:
3279 return(1);
3280 }
3281 return(1);
3282}
3283
Daniel Veillard4432df22003-09-28 18:58:27 +00003284#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003285/**
3286 * xmlValidateNameValue:
3287 * @value: an Name value
3288 *
3289 * Validate that the given value match Name production
3290 *
3291 * returns 1 if valid or 0 otherwise
3292 */
3293
Daniel Veillard9b731d72002-04-14 12:56:08 +00003294int
Owen Taylor3473f882001-02-23 17:55:21 +00003295xmlValidateNameValue(const xmlChar *value) {
3296 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003297 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003298
3299 if (value == NULL) return(0);
3300 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003301 val = xmlStringCurrentChar(NULL, cur, &len);
3302 cur += len;
3303 if (!IS_LETTER(val) && (val != '_') &&
3304 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003305 return(0);
3306 }
3307
Daniel Veillardd8224e02002-01-13 15:43:22 +00003308 val = xmlStringCurrentChar(NULL, cur, &len);
3309 cur += len;
3310 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3311 (val == '.') || (val == '-') ||
3312 (val == '_') || (val == ':') ||
3313 (IS_COMBINING(val)) ||
3314 (IS_EXTENDER(val))) {
3315 val = xmlStringCurrentChar(NULL, cur, &len);
3316 cur += len;
3317 }
Owen Taylor3473f882001-02-23 17:55:21 +00003318
Daniel Veillardd8224e02002-01-13 15:43:22 +00003319 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003320
3321 return(1);
3322}
3323
3324/**
3325 * xmlValidateNamesValue:
3326 * @value: an Names value
3327 *
3328 * Validate that the given value match Names production
3329 *
3330 * returns 1 if valid or 0 otherwise
3331 */
3332
Daniel Veillard9b731d72002-04-14 12:56:08 +00003333int
Owen Taylor3473f882001-02-23 17:55:21 +00003334xmlValidateNamesValue(const xmlChar *value) {
3335 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003336 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003337
3338 if (value == NULL) return(0);
3339 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003340 val = xmlStringCurrentChar(NULL, cur, &len);
3341 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003342
Daniel Veillardd8224e02002-01-13 15:43:22 +00003343 if (!IS_LETTER(val) && (val != '_') &&
3344 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003345 return(0);
3346 }
3347
Daniel Veillardd8224e02002-01-13 15:43:22 +00003348 val = xmlStringCurrentChar(NULL, cur, &len);
3349 cur += len;
3350 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3351 (val == '.') || (val == '-') ||
3352 (val == '_') || (val == ':') ||
3353 (IS_COMBINING(val)) ||
3354 (IS_EXTENDER(val))) {
3355 val = xmlStringCurrentChar(NULL, cur, &len);
3356 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003357 }
3358
Daniel Veillard807b4de2004-09-26 14:42:56 +00003359 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3360 while (val == 0x20) {
3361 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003362 val = xmlStringCurrentChar(NULL, cur, &len);
3363 cur += len;
3364 }
3365
3366 if (!IS_LETTER(val) && (val != '_') &&
3367 (val != ':')) {
3368 return(0);
3369 }
3370 val = xmlStringCurrentChar(NULL, cur, &len);
3371 cur += len;
3372
3373 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3374 (val == '.') || (val == '-') ||
3375 (val == '_') || (val == ':') ||
3376 (IS_COMBINING(val)) ||
3377 (IS_EXTENDER(val))) {
3378 val = xmlStringCurrentChar(NULL, cur, &len);
3379 cur += len;
3380 }
3381 }
3382
3383 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003384
3385 return(1);
3386}
3387
3388/**
3389 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003390 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003391 *
3392 * Validate that the given value match Nmtoken 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 +00003400xmlValidateNmtokenValue(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 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3410 (val != '.') && (val != '-') &&
3411 (val != '_') && (val != ':') &&
3412 (!IS_COMBINING(val)) &&
3413 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003414 return(0);
3415
Daniel Veillardd8224e02002-01-13 15:43:22 +00003416 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3417 (val == '.') || (val == '-') ||
3418 (val == '_') || (val == ':') ||
3419 (IS_COMBINING(val)) ||
3420 (IS_EXTENDER(val))) {
3421 val = xmlStringCurrentChar(NULL, cur, &len);
3422 cur += len;
3423 }
Owen Taylor3473f882001-02-23 17:55:21 +00003424
Daniel Veillardd8224e02002-01-13 15:43:22 +00003425 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003426
3427 return(1);
3428}
3429
3430/**
3431 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003432 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003433 *
3434 * Validate that the given value match Nmtokens production
3435 *
3436 * [ VC: Name Token ]
3437 *
3438 * returns 1 if valid or 0 otherwise
3439 */
3440
Daniel Veillard9b731d72002-04-14 12:56:08 +00003441int
Owen Taylor3473f882001-02-23 17:55:21 +00003442xmlValidateNmtokensValue(const xmlChar *value) {
3443 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003444 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003445
3446 if (value == NULL) return(0);
3447 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003448 val = xmlStringCurrentChar(NULL, cur, &len);
3449 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003450
Daniel Veillardd8224e02002-01-13 15:43:22 +00003451 while (IS_BLANK(val)) {
3452 val = xmlStringCurrentChar(NULL, cur, &len);
3453 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003454 }
3455
Daniel Veillardd8224e02002-01-13 15:43:22 +00003456 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3457 (val != '.') && (val != '-') &&
3458 (val != '_') && (val != ':') &&
3459 (!IS_COMBINING(val)) &&
3460 (!IS_EXTENDER(val)))
3461 return(0);
3462
3463 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3464 (val == '.') || (val == '-') ||
3465 (val == '_') || (val == ':') ||
3466 (IS_COMBINING(val)) ||
3467 (IS_EXTENDER(val))) {
3468 val = xmlStringCurrentChar(NULL, cur, &len);
3469 cur += len;
3470 }
3471
Daniel Veillard807b4de2004-09-26 14:42:56 +00003472 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3473 while (val == 0x20) {
3474 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003475 val = xmlStringCurrentChar(NULL, cur, &len);
3476 cur += len;
3477 }
3478 if (val == 0) return(1);
3479
3480 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3481 (val != '.') && (val != '-') &&
3482 (val != '_') && (val != ':') &&
3483 (!IS_COMBINING(val)) &&
3484 (!IS_EXTENDER(val)))
3485 return(0);
3486
3487 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3488 (val == '.') || (val == '-') ||
3489 (val == '_') || (val == ':') ||
3490 (IS_COMBINING(val)) ||
3491 (IS_EXTENDER(val))) {
3492 val = xmlStringCurrentChar(NULL, cur, &len);
3493 cur += len;
3494 }
3495 }
3496
3497 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003498
3499 return(1);
3500}
3501
3502/**
3503 * xmlValidateNotationDecl:
3504 * @ctxt: the validation context
3505 * @doc: a document instance
3506 * @nota: a notation definition
3507 *
3508 * Try to validate a single notation definition
3509 * basically it does the following checks as described by the
3510 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003511 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003512 * But this function get called anyway ...
3513 *
3514 * returns 1 if valid or 0 otherwise
3515 */
3516
3517int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003518xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3519 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003520 int ret = 1;
3521
3522 return(ret);
3523}
3524
3525/**
3526 * xmlValidateAttributeValue:
3527 * @type: an attribute type
3528 * @value: an attribute value
3529 *
3530 * Validate that the given attribute value match the proper production
3531 *
3532 * [ VC: ID ]
3533 * Values of type ID must match the Name production....
3534 *
3535 * [ VC: IDREF ]
3536 * Values of type IDREF must match the Name production, and values
3537 * of type IDREFS must match Names ...
3538 *
3539 * [ VC: Entity Name ]
3540 * Values of type ENTITY must match the Name production, values
3541 * of type ENTITIES must match Names ...
3542 *
3543 * [ VC: Name Token ]
3544 * Values of type NMTOKEN must match the Nmtoken production; values
3545 * of type NMTOKENS must match Nmtokens.
3546 *
3547 * returns 1 if valid or 0 otherwise
3548 */
3549
3550int
3551xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3552 switch (type) {
3553 case XML_ATTRIBUTE_ENTITIES:
3554 case XML_ATTRIBUTE_IDREFS:
3555 return(xmlValidateNamesValue(value));
3556 case XML_ATTRIBUTE_ENTITY:
3557 case XML_ATTRIBUTE_IDREF:
3558 case XML_ATTRIBUTE_ID:
3559 case XML_ATTRIBUTE_NOTATION:
3560 return(xmlValidateNameValue(value));
3561 case XML_ATTRIBUTE_NMTOKENS:
3562 case XML_ATTRIBUTE_ENUMERATION:
3563 return(xmlValidateNmtokensValue(value));
3564 case XML_ATTRIBUTE_NMTOKEN:
3565 return(xmlValidateNmtokenValue(value));
3566 case XML_ATTRIBUTE_CDATA:
3567 break;
3568 }
3569 return(1);
3570}
3571
3572/**
3573 * xmlValidateAttributeValue2:
3574 * @ctxt: the validation context
3575 * @doc: the document
3576 * @name: the attribute name (used for error reporting only)
3577 * @type: the attribute type
3578 * @value: the attribute value
3579 *
3580 * Validate that the given attribute value match a given type.
3581 * This typically cannot be done before having finished parsing
3582 * the subsets.
3583 *
3584 * [ VC: IDREF ]
3585 * Values of type IDREF must match one of the declared IDs
3586 * Values of type IDREFS must match a sequence of the declared IDs
3587 * each Name must match the value of an ID attribute on some element
3588 * in the XML document; i.e. IDREF values must match the value of
3589 * some ID attribute
3590 *
3591 * [ VC: Entity Name ]
3592 * Values of type ENTITY must match one declared entity
3593 * Values of type ENTITIES must match a sequence of declared entities
3594 *
3595 * [ VC: Notation Attributes ]
3596 * all notation names in the declaration must be declared.
3597 *
3598 * returns 1 if valid or 0 otherwise
3599 */
3600
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003601static int
Owen Taylor3473f882001-02-23 17:55:21 +00003602xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3603 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3604 int ret = 1;
3605 switch (type) {
3606 case XML_ATTRIBUTE_IDREFS:
3607 case XML_ATTRIBUTE_IDREF:
3608 case XML_ATTRIBUTE_ID:
3609 case XML_ATTRIBUTE_NMTOKENS:
3610 case XML_ATTRIBUTE_ENUMERATION:
3611 case XML_ATTRIBUTE_NMTOKEN:
3612 case XML_ATTRIBUTE_CDATA:
3613 break;
3614 case XML_ATTRIBUTE_ENTITY: {
3615 xmlEntityPtr ent;
3616
3617 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003618 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003619 if ((ent == NULL) && (doc->standalone == 1)) {
3620 doc->standalone = 0;
3621 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003622 }
Owen Taylor3473f882001-02-23 17:55:21 +00003623 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003624 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3625 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003626 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003627 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003628 ret = 0;
3629 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003630 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3631 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003632 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003633 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003634 ret = 0;
3635 }
3636 break;
3637 }
3638 case XML_ATTRIBUTE_ENTITIES: {
3639 xmlChar *dup, *nam = NULL, *cur, save;
3640 xmlEntityPtr ent;
3641
3642 dup = xmlStrdup(value);
3643 if (dup == NULL)
3644 return(0);
3645 cur = dup;
3646 while (*cur != 0) {
3647 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003648 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003649 save = *cur;
3650 *cur = 0;
3651 ent = xmlGetDocEntity(doc, nam);
3652 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003653 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3654 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003655 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003656 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003657 ret = 0;
3658 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003659 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3660 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003661 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003662 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003663 ret = 0;
3664 }
3665 if (save == 0)
3666 break;
3667 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003668 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003669 }
3670 xmlFree(dup);
3671 break;
3672 }
3673 case XML_ATTRIBUTE_NOTATION: {
3674 xmlNotationPtr nota;
3675
3676 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3677 if ((nota == NULL) && (doc->extSubset != NULL))
3678 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3679
3680 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003681 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3682 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003683 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003684 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003685 ret = 0;
3686 }
3687 break;
3688 }
3689 }
3690 return(ret);
3691}
3692
3693/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003694 * xmlValidCtxtNormalizeAttributeValue:
3695 * @ctxt: the validation context
3696 * @doc: the document
3697 * @elem: the parent
3698 * @name: the attribute name
3699 * @value: the attribute value
3700 * @ctxt: the validation context or NULL
3701 *
3702 * Does the validation related extra step of the normalization of attribute
3703 * values:
3704 *
3705 * If the declared value is not CDATA, then the XML processor must further
3706 * process the normalized attribute value by discarding any leading and
3707 * trailing space (#x20) characters, and by replacing sequences of space
3708 * (#x20) characters by single space (#x20) character.
3709 *
3710 * Also check VC: Standalone Document Declaration in P32, and update
3711 * ctxt->valid accordingly
3712 *
3713 * returns a new normalized string if normalization is needed, NULL otherwise
3714 * the caller must free the returned value.
3715 */
3716
3717xmlChar *
3718xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3719 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3720 xmlChar *ret, *dst;
3721 const xmlChar *src;
3722 xmlAttributePtr attrDecl = NULL;
3723 int extsubset = 0;
3724
3725 if (doc == NULL) return(NULL);
3726 if (elem == NULL) return(NULL);
3727 if (name == NULL) return(NULL);
3728 if (value == NULL) return(NULL);
3729
3730 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003731 xmlChar fn[50];
3732 xmlChar *fullname;
3733
3734 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3735 if (fullname == NULL)
3736 return(0);
3737 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003738 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003739 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003740 if (attrDecl != NULL)
3741 extsubset = 1;
3742 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003743 if ((fullname != fn) && (fullname != elem->name))
3744 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003745 }
3746 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3747 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3748 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3749 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3750 if (attrDecl != NULL)
3751 extsubset = 1;
3752 }
3753
3754 if (attrDecl == NULL)
3755 return(NULL);
3756 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3757 return(NULL);
3758
3759 ret = xmlStrdup(value);
3760 if (ret == NULL)
3761 return(NULL);
3762 src = value;
3763 dst = ret;
3764 while (*src == 0x20) src++;
3765 while (*src != 0) {
3766 if (*src == 0x20) {
3767 while (*src == 0x20) src++;
3768 if (*src != 0)
3769 *dst++ = 0x20;
3770 } else {
3771 *dst++ = *src++;
3772 }
3773 }
3774 *dst = 0;
3775 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003776 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003777"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003778 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003779 ctxt->valid = 0;
3780 }
3781 return(ret);
3782}
3783
3784/**
Owen Taylor3473f882001-02-23 17:55:21 +00003785 * xmlValidNormalizeAttributeValue:
3786 * @doc: the document
3787 * @elem: the parent
3788 * @name: the attribute name
3789 * @value: the attribute value
3790 *
3791 * Does the validation related extra step of the normalization of attribute
3792 * values:
3793 *
3794 * If the declared value is not CDATA, then the XML processor must further
3795 * process the normalized attribute value by discarding any leading and
3796 * trailing space (#x20) characters, and by replacing sequences of space
3797 * (#x20) characters by single space (#x20) character.
3798 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003799 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003800 * the caller must free the returned value.
3801 */
3802
3803xmlChar *
3804xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3805 const xmlChar *name, const xmlChar *value) {
3806 xmlChar *ret, *dst;
3807 const xmlChar *src;
3808 xmlAttributePtr attrDecl = NULL;
3809
3810 if (doc == NULL) return(NULL);
3811 if (elem == NULL) return(NULL);
3812 if (name == NULL) return(NULL);
3813 if (value == NULL) return(NULL);
3814
3815 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003816 xmlChar fn[50];
3817 xmlChar *fullname;
3818
3819 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3820 if (fullname == NULL)
3821 return(0);
3822 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003823 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003824 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3825 if ((fullname != fn) && (fullname != elem->name))
3826 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003827 }
3828 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3829 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3830 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3831
3832 if (attrDecl == NULL)
3833 return(NULL);
3834 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3835 return(NULL);
3836
3837 ret = xmlStrdup(value);
3838 if (ret == NULL)
3839 return(NULL);
3840 src = value;
3841 dst = ret;
3842 while (*src == 0x20) src++;
3843 while (*src != 0) {
3844 if (*src == 0x20) {
3845 while (*src == 0x20) src++;
3846 if (*src != 0)
3847 *dst++ = 0x20;
3848 } else {
3849 *dst++ = *src++;
3850 }
3851 }
3852 *dst = 0;
3853 return(ret);
3854}
3855
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003856static void
Owen Taylor3473f882001-02-23 17:55:21 +00003857xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003858 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003859 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3860}
3861
3862/**
3863 * xmlValidateAttributeDecl:
3864 * @ctxt: the validation context
3865 * @doc: a document instance
3866 * @attr: an attribute definition
3867 *
3868 * Try to validate a single attribute definition
3869 * basically it does the following checks as described by the
3870 * XML-1.0 recommendation:
3871 * - [ VC: Attribute Default Legal ]
3872 * - [ VC: Enumeration ]
3873 * - [ VC: ID Attribute Default ]
3874 *
3875 * The ID/IDREF uniqueness and matching are done separately
3876 *
3877 * returns 1 if valid or 0 otherwise
3878 */
3879
3880int
3881xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3882 xmlAttributePtr attr) {
3883 int ret = 1;
3884 int val;
3885 CHECK_DTD;
3886 if(attr == NULL) return(1);
3887
3888 /* Attribute Default Legal */
3889 /* Enumeration */
3890 if (attr->defaultValue != NULL) {
3891 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3892 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003893 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003894 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003895 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003896 }
3897 ret &= val;
3898 }
3899
3900 /* ID Attribute Default */
3901 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3902 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3903 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003904 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003905 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003906 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003907 ret = 0;
3908 }
3909
3910 /* One ID per Element Type */
3911 if (attr->atype == XML_ATTRIBUTE_ID) {
3912 int nbId;
3913
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003914 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00003915 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3916 attr->elem);
3917 if (elem != NULL) {
3918 nbId = xmlScanIDAttributeDecl(NULL, elem);
3919 } else {
3920 xmlAttributeTablePtr table;
3921
3922 /*
3923 * The attribute may be declared in the internal subset and the
3924 * element in the external subset.
3925 */
3926 nbId = 0;
3927 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3928 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3929 xmlValidateAttributeIdCallback, &nbId);
3930 }
3931 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003932
3933 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003934 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3935 attr->elem, nbId, attr->name);
3936 } else if (doc->extSubset != NULL) {
3937 int extId = 0;
3938 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3939 if (elem != NULL) {
3940 extId = xmlScanIDAttributeDecl(NULL, elem);
3941 }
3942 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003943 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003944 "Element %s has %d ID attribute defined in the external subset : %s\n",
3945 attr->elem, extId, attr->name);
3946 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003947 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003948"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003949 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003950 }
3951 }
3952 }
3953
3954 /* Validity Constraint: Enumeration */
3955 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3956 xmlEnumerationPtr tree = attr->tree;
3957 while (tree != NULL) {
3958 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3959 tree = tree->next;
3960 }
3961 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003962 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003963"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003964 attr->defaultValue, attr->name, attr->elem);
3965 ret = 0;
3966 }
3967 }
3968
3969 return(ret);
3970}
3971
3972/**
3973 * xmlValidateElementDecl:
3974 * @ctxt: the validation context
3975 * @doc: a document instance
3976 * @elem: an element definition
3977 *
3978 * Try to validate a single element definition
3979 * basically it does the following checks as described by the
3980 * XML-1.0 recommendation:
3981 * - [ VC: One ID per Element Type ]
3982 * - [ VC: No Duplicate Types ]
3983 * - [ VC: Unique Element Type Declaration ]
3984 *
3985 * returns 1 if valid or 0 otherwise
3986 */
3987
3988int
3989xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3990 xmlElementPtr elem) {
3991 int ret = 1;
3992 xmlElementPtr tst;
3993
3994 CHECK_DTD;
3995
3996 if (elem == NULL) return(1);
3997
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003998#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00003999#ifdef LIBXML_REGEXP_ENABLED
4000 /* Build the regexp associated to the content model */
4001 ret = xmlValidBuildContentModel(ctxt, elem);
4002#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004003#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00004004
Owen Taylor3473f882001-02-23 17:55:21 +00004005 /* No Duplicate Types */
4006 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4007 xmlElementContentPtr cur, next;
4008 const xmlChar *name;
4009
4010 cur = elem->content;
4011 while (cur != NULL) {
4012 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4013 if (cur->c1 == NULL) break;
4014 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4015 name = cur->c1->name;
4016 next = cur->c2;
4017 while (next != NULL) {
4018 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00004019 if ((xmlStrEqual(next->name, name)) &&
4020 (xmlStrEqual(next->prefix, cur->prefix))) {
4021 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004022 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00004023 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004024 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004025 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004026 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004027 "Definition of %s has duplicate references of %s:%s\n",
4028 elem->name, cur->prefix, name);
4029 }
Owen Taylor3473f882001-02-23 17:55:21 +00004030 ret = 0;
4031 }
4032 break;
4033 }
4034 if (next->c1 == NULL) break;
4035 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00004036 if ((xmlStrEqual(next->c1->name, name)) &&
4037 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
4038 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004039 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004040 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004041 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004042 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004043 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004044 "Definition of %s has duplicate references to %s:%s\n",
4045 elem->name, cur->prefix, name);
4046 }
Owen Taylor3473f882001-02-23 17:55:21 +00004047 ret = 0;
4048 }
4049 next = next->c2;
4050 }
4051 }
4052 cur = cur->c2;
4053 }
4054 }
4055
4056 /* VC: Unique Element Type Declaration */
4057 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004058 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004059 ((tst->prefix == elem->prefix) ||
4060 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004061 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004062 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4063 "Redefinition of element %s\n",
4064 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004065 ret = 0;
4066 }
4067 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004068 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004069 ((tst->prefix == elem->prefix) ||
4070 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004071 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004072 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4073 "Redefinition of element %s\n",
4074 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004075 ret = 0;
4076 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004077 /* One ID per Element Type
4078 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004079 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4080 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004081 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004082 return(ret);
4083}
4084
4085/**
4086 * xmlValidateOneAttribute:
4087 * @ctxt: the validation context
4088 * @doc: a document instance
4089 * @elem: an element instance
4090 * @attr: an attribute instance
4091 * @value: the attribute value (without entities processing)
4092 *
4093 * Try to validate a single attribute for an element
4094 * basically it does the following checks as described by the
4095 * XML-1.0 recommendation:
4096 * - [ VC: Attribute Value Type ]
4097 * - [ VC: Fixed Attribute Default ]
4098 * - [ VC: Entity Name ]
4099 * - [ VC: Name Token ]
4100 * - [ VC: ID ]
4101 * - [ VC: IDREF ]
4102 * - [ VC: Entity Name ]
4103 * - [ VC: Notation Attributes ]
4104 *
4105 * The ID/IDREF uniqueness and matching are done separately
4106 *
4107 * returns 1 if valid or 0 otherwise
4108 */
4109
4110int
4111xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004112 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4113{
Owen Taylor3473f882001-02-23 17:55:21 +00004114 xmlAttributePtr attrDecl = NULL;
4115 int val;
4116 int ret = 1;
4117
4118 CHECK_DTD;
4119 if ((elem == NULL) || (elem->name == NULL)) return(0);
4120 if ((attr == NULL) || (attr->name == NULL)) return(0);
4121
4122 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004123 xmlChar fn[50];
4124 xmlChar *fullname;
4125
4126 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4127 if (fullname == NULL)
4128 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004129 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004130 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004131 attr->name, attr->ns->prefix);
4132 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004133 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004134 attr->name, attr->ns->prefix);
4135 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004136 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004137 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4138 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004139 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004140 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004141 if ((fullname != fn) && (fullname != elem->name))
4142 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004143 }
4144 if (attrDecl == NULL) {
4145 if (attr->ns != NULL) {
4146 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4147 attr->name, attr->ns->prefix);
4148 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4149 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4150 attr->name, attr->ns->prefix);
4151 } else {
4152 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4153 elem->name, attr->name);
4154 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4155 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4156 elem->name, attr->name);
4157 }
4158 }
4159
4160
4161 /* Validity Constraint: Attribute Value Type */
4162 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004163 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004164 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004165 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004166 return(0);
4167 }
4168 attr->atype = attrDecl->atype;
4169
4170 val = xmlValidateAttributeValue(attrDecl->atype, value);
4171 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004172 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004173 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004174 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004175 ret = 0;
4176 }
4177
4178 /* Validity constraint: Fixed Attribute Default */
4179 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4180 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004181 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004182 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004183 attr->name, elem->name, attrDecl->defaultValue);
4184 ret = 0;
4185 }
4186 }
4187
4188 /* Validity Constraint: ID uniqueness */
4189 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4190 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4191 ret = 0;
4192 }
4193
4194 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4195 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4196 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4197 ret = 0;
4198 }
4199
4200 /* Validity Constraint: Notation Attributes */
4201 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4202 xmlEnumerationPtr tree = attrDecl->tree;
4203 xmlNotationPtr nota;
4204
4205 /* First check that the given NOTATION was declared */
4206 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4207 if (nota == NULL)
4208 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4209
4210 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004211 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004212 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004213 value, attr->name, elem->name);
4214 ret = 0;
4215 }
4216
4217 /* Second, verify that it's among the list */
4218 while (tree != NULL) {
4219 if (xmlStrEqual(tree->name, value)) break;
4220 tree = tree->next;
4221 }
4222 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004223 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004224"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004225 value, attr->name, elem->name);
4226 ret = 0;
4227 }
4228 }
4229
4230 /* Validity Constraint: Enumeration */
4231 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4232 xmlEnumerationPtr tree = attrDecl->tree;
4233 while (tree != NULL) {
4234 if (xmlStrEqual(tree->name, value)) break;
4235 tree = tree->next;
4236 }
4237 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004238 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004239 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004240 value, attr->name, elem->name);
4241 ret = 0;
4242 }
4243 }
4244
4245 /* Fixed Attribute Default */
4246 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4247 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004248 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004249 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004250 attr->name, elem->name, attrDecl->defaultValue);
4251 ret = 0;
4252 }
4253
4254 /* Extra check for the attribute value */
4255 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4256 attrDecl->atype, value);
4257
4258 return(ret);
4259}
4260
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004261/**
4262 * xmlValidateOneNamespace:
4263 * @ctxt: the validation context
4264 * @doc: a document instance
4265 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004266 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004267 * @ns: an namespace declaration instance
4268 * @value: the attribute value (without entities processing)
4269 *
4270 * Try to validate a single namespace declaration for an element
4271 * basically it does the following checks as described by the
4272 * XML-1.0 recommendation:
4273 * - [ VC: Attribute Value Type ]
4274 * - [ VC: Fixed Attribute Default ]
4275 * - [ VC: Entity Name ]
4276 * - [ VC: Name Token ]
4277 * - [ VC: ID ]
4278 * - [ VC: IDREF ]
4279 * - [ VC: Entity Name ]
4280 * - [ VC: Notation Attributes ]
4281 *
4282 * The ID/IDREF uniqueness and matching are done separately
4283 *
4284 * returns 1 if valid or 0 otherwise
4285 */
4286
4287int
4288xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4289xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4290 /* xmlElementPtr elemDecl; */
4291 xmlAttributePtr attrDecl = NULL;
4292 int val;
4293 int ret = 1;
4294
4295 CHECK_DTD;
4296 if ((elem == NULL) || (elem->name == NULL)) return(0);
4297 if ((ns == NULL) || (ns->href == NULL)) return(0);
4298
4299 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004300 xmlChar fn[50];
4301 xmlChar *fullname;
4302
4303 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4304 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004305 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004306 return(0);
4307 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004308 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004309 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004310 ns->prefix, BAD_CAST "xmlns");
4311 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004312 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004313 ns->prefix, BAD_CAST "xmlns");
4314 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004315 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004316 BAD_CAST "xmlns");
4317 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004318 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004319 BAD_CAST "xmlns");
4320 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004321 if ((fullname != fn) && (fullname != elem->name))
4322 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004323 }
4324 if (attrDecl == NULL) {
4325 if (ns->prefix != NULL) {
4326 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4327 ns->prefix, BAD_CAST "xmlns");
4328 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4329 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4330 ns->prefix, BAD_CAST "xmlns");
4331 } else {
4332 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4333 elem->name, BAD_CAST "xmlns");
4334 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4335 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4336 elem->name, BAD_CAST "xmlns");
4337 }
4338 }
4339
4340
4341 /* Validity Constraint: Attribute Value Type */
4342 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004343 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004344 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004345 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004346 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004347 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004348 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004349 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004350 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004351 }
4352 return(0);
4353 }
4354
4355 val = xmlValidateAttributeValue(attrDecl->atype, value);
4356 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004357 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004358 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004359 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004360 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004361 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004362 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004363 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004364 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004365 }
4366 ret = 0;
4367 }
4368
4369 /* Validity constraint: Fixed Attribute Default */
4370 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4371 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004372 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004373 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004374 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4375 ns->prefix, elem->name, attrDecl->defaultValue);
4376 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004377 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004378 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004379 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004380 }
4381 ret = 0;
4382 }
4383 }
4384
4385 /* Validity Constraint: ID uniqueness */
4386 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4387 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4388 ret = 0;
4389 }
4390
4391 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4392 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4393 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4394 ret = 0;
4395 }
4396
4397 /* Validity Constraint: Notation Attributes */
4398 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4399 xmlEnumerationPtr tree = attrDecl->tree;
4400 xmlNotationPtr nota;
4401
4402 /* First check that the given NOTATION was declared */
4403 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4404 if (nota == NULL)
4405 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4406
4407 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004408 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004409 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004410 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4411 value, ns->prefix, elem->name);
4412 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004413 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004414 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004415 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004416 }
4417 ret = 0;
4418 }
4419
4420 /* Second, verify that it's among the list */
4421 while (tree != NULL) {
4422 if (xmlStrEqual(tree->name, value)) break;
4423 tree = tree->next;
4424 }
4425 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004426 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004427 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004428"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4429 value, ns->prefix, elem->name);
4430 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004431 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004432"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004433 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004434 }
4435 ret = 0;
4436 }
4437 }
4438
4439 /* Validity Constraint: Enumeration */
4440 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4441 xmlEnumerationPtr tree = attrDecl->tree;
4442 while (tree != NULL) {
4443 if (xmlStrEqual(tree->name, value)) break;
4444 tree = tree->next;
4445 }
4446 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004447 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004448 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004449"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4450 value, ns->prefix, elem->name);
4451 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004452 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004453"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004454 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004455 }
4456 ret = 0;
4457 }
4458 }
4459
4460 /* Fixed Attribute Default */
4461 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4462 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004463 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004464 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004465 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4466 ns->prefix, elem->name, attrDecl->defaultValue);
4467 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004468 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004469 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004470 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004471 }
4472 ret = 0;
4473 }
4474
4475 /* Extra check for the attribute value */
4476 if (ns->prefix != NULL) {
4477 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4478 attrDecl->atype, value);
4479 } else {
4480 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4481 attrDecl->atype, value);
4482 }
4483
4484 return(ret);
4485}
4486
Daniel Veillard118aed72002-09-24 14:13:13 +00004487#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004488/**
4489 * xmlValidateSkipIgnorable:
4490 * @ctxt: the validation context
4491 * @child: the child list
4492 *
4493 * Skip ignorable elements w.r.t. the validation process
4494 *
4495 * returns the first element to consider for validation of the content model
4496 */
4497
4498static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004499xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004500 while (child != NULL) {
4501 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004502 /* These things are ignored (skipped) during validation. */
4503 case XML_PI_NODE:
4504 case XML_COMMENT_NODE:
4505 case XML_XINCLUDE_START:
4506 case XML_XINCLUDE_END:
4507 child = child->next;
4508 break;
4509 case XML_TEXT_NODE:
4510 if (xmlIsBlankNode(child))
4511 child = child->next;
4512 else
4513 return(child);
4514 break;
4515 /* keep current node */
4516 default:
4517 return(child);
4518 }
4519 }
4520 return(child);
4521}
4522
4523/**
4524 * xmlValidateElementType:
4525 * @ctxt: the validation context
4526 *
4527 * Try to validate the content model of an element internal function
4528 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004529 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4530 * reference is found and -3 if the validation succeeded but
4531 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004532 */
4533
4534static int
4535xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004536 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004537 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004538
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004539 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004540 if ((NODE == NULL) && (CONT == NULL))
4541 return(1);
4542 if ((NODE == NULL) &&
4543 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4544 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4545 return(1);
4546 }
4547 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004548 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004549 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004550
4551 /*
4552 * We arrive here when more states need to be examined
4553 */
4554cont:
4555
4556 /*
4557 * We just recovered from a rollback generated by a possible
4558 * epsilon transition, go directly to the analysis phase
4559 */
4560 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004561 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004562 DEBUG_VALID_STATE(NODE, CONT)
4563 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004564 goto analyze;
4565 }
4566
4567 DEBUG_VALID_STATE(NODE, CONT)
4568 /*
4569 * we may have to save a backup state here. This is the equivalent
4570 * of handling epsilon transition in NFAs.
4571 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004572 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004573 ((CONT->parent == NULL) ||
4574 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004575 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004576 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004577 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004578 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004579 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4580 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004581 }
4582
4583
4584 /*
4585 * Check first if the content matches
4586 */
4587 switch (CONT->type) {
4588 case XML_ELEMENT_CONTENT_PCDATA:
4589 if (NODE == NULL) {
4590 DEBUG_VALID_MSG("pcdata failed no node");
4591 ret = 0;
4592 break;
4593 }
4594 if (NODE->type == XML_TEXT_NODE) {
4595 DEBUG_VALID_MSG("pcdata found, skip to next");
4596 /*
4597 * go to next element in the content model
4598 * skipping ignorable elems
4599 */
4600 do {
4601 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004602 NODE = xmlValidateSkipIgnorable(NODE);
4603 if ((NODE != NULL) &&
4604 (NODE->type == XML_ENTITY_REF_NODE))
4605 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004606 } while ((NODE != NULL) &&
4607 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004608 (NODE->type != XML_TEXT_NODE) &&
4609 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004610 ret = 1;
4611 break;
4612 } else {
4613 DEBUG_VALID_MSG("pcdata failed");
4614 ret = 0;
4615 break;
4616 }
4617 break;
4618 case XML_ELEMENT_CONTENT_ELEMENT:
4619 if (NODE == NULL) {
4620 DEBUG_VALID_MSG("element failed no node");
4621 ret = 0;
4622 break;
4623 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004624 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4625 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004626 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004627 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4628 ret = (CONT->prefix == NULL);
4629 } else if (CONT->prefix == NULL) {
4630 ret = 0;
4631 } else {
4632 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4633 }
4634 }
4635 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004636 DEBUG_VALID_MSG("element found, skip to next");
4637 /*
4638 * go to next element in the content model
4639 * skipping ignorable elems
4640 */
4641 do {
4642 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004643 NODE = xmlValidateSkipIgnorable(NODE);
4644 if ((NODE != NULL) &&
4645 (NODE->type == XML_ENTITY_REF_NODE))
4646 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004647 } while ((NODE != NULL) &&
4648 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004649 (NODE->type != XML_TEXT_NODE) &&
4650 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004651 } else {
4652 DEBUG_VALID_MSG("element failed");
4653 ret = 0;
4654 break;
4655 }
4656 break;
4657 case XML_ELEMENT_CONTENT_OR:
4658 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004659 * Small optimization.
4660 */
4661 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4662 if ((NODE == NULL) ||
4663 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4664 DEPTH++;
4665 CONT = CONT->c2;
4666 goto cont;
4667 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004668 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4669 ret = (CONT->c1->prefix == NULL);
4670 } else if (CONT->c1->prefix == NULL) {
4671 ret = 0;
4672 } else {
4673 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4674 }
4675 if (ret == 0) {
4676 DEPTH++;
4677 CONT = CONT->c2;
4678 goto cont;
4679 }
Daniel Veillard85349052001-04-20 13:48:21 +00004680 }
4681
4682 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004683 * save the second branch 'or' branch
4684 */
4685 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004686 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4687 OCCURS, ROLLBACK_OR) < 0)
4688 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004689 DEPTH++;
4690 CONT = CONT->c1;
4691 goto cont;
4692 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004693 /*
4694 * Small optimization.
4695 */
4696 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4697 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4698 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4699 if ((NODE == NULL) ||
4700 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4701 DEPTH++;
4702 CONT = CONT->c2;
4703 goto cont;
4704 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004705 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4706 ret = (CONT->c1->prefix == NULL);
4707 } else if (CONT->c1->prefix == NULL) {
4708 ret = 0;
4709 } else {
4710 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4711 }
4712 if (ret == 0) {
4713 DEPTH++;
4714 CONT = CONT->c2;
4715 goto cont;
4716 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004717 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004718 DEPTH++;
4719 CONT = CONT->c1;
4720 goto cont;
4721 }
4722
4723 /*
4724 * At this point handle going up in the tree
4725 */
4726 if (ret == -1) {
4727 DEBUG_VALID_MSG("error found returning");
4728 return(ret);
4729 }
4730analyze:
4731 while (CONT != NULL) {
4732 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004733 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004734 * this level.
4735 */
4736 if (ret == 0) {
4737 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004738 xmlNodePtr cur;
4739
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004740 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004741 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004742 DEBUG_VALID_MSG("Once branch failed, rollback");
4743 if (vstateVPop(ctxt) < 0 ) {
4744 DEBUG_VALID_MSG("exhaustion, failed");
4745 return(0);
4746 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004747 if (cur != ctxt->vstate->node)
4748 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004749 goto cont;
4750 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004751 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004752 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004753 DEBUG_VALID_MSG("Plus branch failed, rollback");
4754 if (vstateVPop(ctxt) < 0 ) {
4755 DEBUG_VALID_MSG("exhaustion, failed");
4756 return(0);
4757 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004758 if (cur != ctxt->vstate->node)
4759 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004760 goto cont;
4761 }
4762 DEBUG_VALID_MSG("Plus branch found");
4763 ret = 1;
4764 break;
4765 case XML_ELEMENT_CONTENT_MULT:
4766#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004767 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004768 DEBUG_VALID_MSG("Mult branch failed");
4769 } else {
4770 DEBUG_VALID_MSG("Mult branch found");
4771 }
4772#endif
4773 ret = 1;
4774 break;
4775 case XML_ELEMENT_CONTENT_OPT:
4776 DEBUG_VALID_MSG("Option branch failed");
4777 ret = 1;
4778 break;
4779 }
4780 } else {
4781 switch (CONT->ocur) {
4782 case XML_ELEMENT_CONTENT_OPT:
4783 DEBUG_VALID_MSG("Option branch succeeded");
4784 ret = 1;
4785 break;
4786 case XML_ELEMENT_CONTENT_ONCE:
4787 DEBUG_VALID_MSG("Once branch succeeded");
4788 ret = 1;
4789 break;
4790 case XML_ELEMENT_CONTENT_PLUS:
4791 if (STATE == ROLLBACK_PARENT) {
4792 DEBUG_VALID_MSG("Plus branch rollback");
4793 ret = 1;
4794 break;
4795 }
4796 if (NODE == NULL) {
4797 DEBUG_VALID_MSG("Plus branch exhausted");
4798 ret = 1;
4799 break;
4800 }
4801 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004802 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004803 goto cont;
4804 case XML_ELEMENT_CONTENT_MULT:
4805 if (STATE == ROLLBACK_PARENT) {
4806 DEBUG_VALID_MSG("Mult branch rollback");
4807 ret = 1;
4808 break;
4809 }
4810 if (NODE == NULL) {
4811 DEBUG_VALID_MSG("Mult branch exhausted");
4812 ret = 1;
4813 break;
4814 }
4815 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004816 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004817 goto cont;
4818 }
4819 }
4820 STATE = 0;
4821
4822 /*
4823 * Then act accordingly at the parent level
4824 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004825 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004826 if (CONT->parent == NULL)
4827 break;
4828
4829 switch (CONT->parent->type) {
4830 case XML_ELEMENT_CONTENT_PCDATA:
4831 DEBUG_VALID_MSG("Error: parent pcdata");
4832 return(-1);
4833 case XML_ELEMENT_CONTENT_ELEMENT:
4834 DEBUG_VALID_MSG("Error: parent element");
4835 return(-1);
4836 case XML_ELEMENT_CONTENT_OR:
4837 if (ret == 1) {
4838 DEBUG_VALID_MSG("Or succeeded");
4839 CONT = CONT->parent;
4840 DEPTH--;
4841 } else {
4842 DEBUG_VALID_MSG("Or failed");
4843 CONT = CONT->parent;
4844 DEPTH--;
4845 }
4846 break;
4847 case XML_ELEMENT_CONTENT_SEQ:
4848 if (ret == 0) {
4849 DEBUG_VALID_MSG("Sequence failed");
4850 CONT = CONT->parent;
4851 DEPTH--;
4852 } else if (CONT == CONT->parent->c1) {
4853 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4854 CONT = CONT->parent->c2;
4855 goto cont;
4856 } else {
4857 DEBUG_VALID_MSG("Sequence succeeded");
4858 CONT = CONT->parent;
4859 DEPTH--;
4860 }
4861 }
4862 }
4863 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004864 xmlNodePtr cur;
4865
4866 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004867 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4868 if (vstateVPop(ctxt) < 0 ) {
4869 DEBUG_VALID_MSG("exhaustion, failed");
4870 return(0);
4871 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004872 if (cur != ctxt->vstate->node)
4873 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004874 goto cont;
4875 }
4876 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004877 xmlNodePtr cur;
4878
4879 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004880 DEBUG_VALID_MSG("Failure, rollback");
4881 if (vstateVPop(ctxt) < 0 ) {
4882 DEBUG_VALID_MSG("exhaustion, failed");
4883 return(0);
4884 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004885 if (cur != ctxt->vstate->node)
4886 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004887 goto cont;
4888 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004889 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004890}
Daniel Veillard23e73572002-09-19 19:56:43 +00004891#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004892
4893/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00004894 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004895 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00004896 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004897 * @content: An element
4898 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4899 *
4900 * This will dump the list of elements to the buffer
4901 * Intended just for the debug routine
4902 */
4903static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00004904xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004905 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00004906 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004907
4908 if (node == NULL) return;
4909 if (glob) strcat(buf, "(");
4910 cur = node;
4911 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004912 len = strlen(buf);
4913 if (size - len < 50) {
4914 if ((size - len > 4) && (buf[len - 1] != '.'))
4915 strcat(buf, " ...");
4916 return;
4917 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004918 switch (cur->type) {
4919 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004920 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004921 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004922 if ((size - len > 4) && (buf[len - 1] != '.'))
4923 strcat(buf, " ...");
4924 return;
4925 }
4926 strcat(buf, (char *) cur->ns->prefix);
4927 strcat(buf, ":");
4928 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004929 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004930 if ((size - len > 4) && (buf[len - 1] != '.'))
4931 strcat(buf, " ...");
4932 return;
4933 }
4934 strcat(buf, (char *) cur->name);
4935 if (cur->next != NULL)
4936 strcat(buf, " ");
4937 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004938 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004939 if (xmlIsBlankNode(cur))
4940 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004941 case XML_CDATA_SECTION_NODE:
4942 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004943 strcat(buf, "CDATA");
4944 if (cur->next != NULL)
4945 strcat(buf, " ");
4946 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004947 case XML_ATTRIBUTE_NODE:
4948 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004949#ifdef LIBXML_DOCB_ENABLED
4950 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004951#endif
4952 case XML_HTML_DOCUMENT_NODE:
4953 case XML_DOCUMENT_TYPE_NODE:
4954 case XML_DOCUMENT_FRAG_NODE:
4955 case XML_NOTATION_NODE:
4956 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004957 strcat(buf, "???");
4958 if (cur->next != NULL)
4959 strcat(buf, " ");
4960 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004961 case XML_ENTITY_NODE:
4962 case XML_PI_NODE:
4963 case XML_DTD_NODE:
4964 case XML_COMMENT_NODE:
4965 case XML_ELEMENT_DECL:
4966 case XML_ATTRIBUTE_DECL:
4967 case XML_ENTITY_DECL:
4968 case XML_XINCLUDE_START:
4969 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004970 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004971 }
4972 cur = cur->next;
4973 }
4974 if (glob) strcat(buf, ")");
4975}
4976
4977/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004978 * xmlValidateElementContent:
4979 * @ctxt: the validation context
4980 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004981 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004982 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004983 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004984 *
4985 * Try to validate the content model of an element
4986 *
4987 * returns 1 if valid or 0 if not and -1 in case of error
4988 */
4989
4990static int
4991xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004992 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004993 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00004994#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00004995 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00004996#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00004997 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004998 xmlElementContentPtr cont;
4999 const xmlChar *name;
5000
5001 if (elemDecl == NULL)
5002 return(-1);
5003 cont = elemDecl->content;
5004 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005005
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005006#ifdef LIBXML_REGEXP_ENABLED
5007 /* Build the regexp associated to the content model */
5008 if (elemDecl->contModel == NULL)
5009 ret = xmlValidBuildContentModel(ctxt, elemDecl);
5010 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005011 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005012 } else {
5013 xmlRegExecCtxtPtr exec;
5014
Daniel Veillardec498e12003-02-05 11:01:50 +00005015 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5016 return(-1);
5017 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005018 ctxt->nodeMax = 0;
5019 ctxt->nodeNr = 0;
5020 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005021 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5022 if (exec != NULL) {
5023 cur = child;
5024 while (cur != NULL) {
5025 switch (cur->type) {
5026 case XML_ENTITY_REF_NODE:
5027 /*
5028 * Push the current node to be able to roll back
5029 * and process within the entity
5030 */
5031 if ((cur->children != NULL) &&
5032 (cur->children->children != NULL)) {
5033 nodeVPush(ctxt, cur);
5034 cur = cur->children->children;
5035 continue;
5036 }
5037 break;
5038 case XML_TEXT_NODE:
5039 if (xmlIsBlankNode(cur))
5040 break;
5041 ret = 0;
5042 goto fail;
5043 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00005044 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005045 ret = 0;
5046 goto fail;
5047 case XML_ELEMENT_NODE:
5048 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005049 xmlChar fn[50];
5050 xmlChar *fullname;
5051
5052 fullname = xmlBuildQName(cur->name,
5053 cur->ns->prefix, fn, 50);
5054 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005055 ret = -1;
5056 goto fail;
5057 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005058 ret = xmlRegExecPushString(exec, fullname, NULL);
5059 if ((fullname != fn) && (fullname != cur->name))
5060 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005061 } else {
5062 ret = xmlRegExecPushString(exec, cur->name, NULL);
5063 }
5064 break;
5065 default:
5066 break;
5067 }
5068 /*
5069 * Switch to next element
5070 */
5071 cur = cur->next;
5072 while (cur == NULL) {
5073 cur = nodeVPop(ctxt);
5074 if (cur == NULL)
5075 break;
5076 cur = cur->next;
5077 }
5078 }
5079 ret = xmlRegExecPushString(exec, NULL, NULL);
5080fail:
5081 xmlRegFreeExecCtxt(exec);
5082 }
5083 }
5084#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005085 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005086 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005087 */
5088 ctxt->vstateMax = 8;
5089 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5090 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5091 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005092 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005093 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005094 }
5095 /*
5096 * The first entry in the stack is reserved to the current state
5097 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005098 ctxt->nodeMax = 0;
5099 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005100 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005101 ctxt->vstate = &ctxt->vstateTab[0];
5102 ctxt->vstateNr = 1;
5103 CONT = cont;
5104 NODE = child;
5105 DEPTH = 0;
5106 OCCURS = 0;
5107 STATE = 0;
5108 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005109 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005110 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5111 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005112 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005113 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005114 /*
5115 * An entities reference appeared at this level.
5116 * Buid a minimal representation of this node content
5117 * sufficient to run the validation process on it
5118 */
5119 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005120 cur = child;
5121 while (cur != NULL) {
5122 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005123 case XML_ENTITY_REF_NODE:
5124 /*
5125 * Push the current node to be able to roll back
5126 * and process within the entity
5127 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005128 if ((cur->children != NULL) &&
5129 (cur->children->children != NULL)) {
5130 nodeVPush(ctxt, cur);
5131 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005132 continue;
5133 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005134 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005135 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005136 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005137 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005138 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005139 case XML_CDATA_SECTION_NODE:
5140 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005141 case XML_ELEMENT_NODE:
5142 /*
5143 * Allocate a new node and minimally fills in
5144 * what's required
5145 */
5146 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5147 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005148 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005149 xmlFreeNodeList(repl);
5150 ret = -1;
5151 goto done;
5152 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005153 tmp->type = cur->type;
5154 tmp->name = cur->name;
5155 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005156 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005157 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005158 if (repl == NULL)
5159 repl = last = tmp;
5160 else {
5161 last->next = tmp;
5162 last = tmp;
5163 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005164 if (cur->type == XML_CDATA_SECTION_NODE) {
5165 /*
5166 * E59 spaces in CDATA does not match the
5167 * nonterminal S
5168 */
5169 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5170 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005171 break;
5172 default:
5173 break;
5174 }
5175 /*
5176 * Switch to next element
5177 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005178 cur = cur->next;
5179 while (cur == NULL) {
5180 cur = nodeVPop(ctxt);
5181 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005182 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005183 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005184 }
5185 }
5186
5187 /*
5188 * Relaunch the validation
5189 */
5190 ctxt->vstate = &ctxt->vstateTab[0];
5191 ctxt->vstateNr = 1;
5192 CONT = cont;
5193 NODE = repl;
5194 DEPTH = 0;
5195 OCCURS = 0;
5196 STATE = 0;
5197 ret = xmlValidateElementType(ctxt);
5198 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005199#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005200 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005201 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5202 char expr[5000];
5203 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005204
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005205 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005206 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005207 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005208#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005209 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005210 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005211 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005212#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005213 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005214
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005215 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005216 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5217 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5218 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005219 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005220 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5221 "Element content does not follow the DTD, expecting %s, got %s\n",
5222 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005223 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005224 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005225 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005226 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005227 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005228 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005229 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005230 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5231 "Element content does not follow the DTD\n",
5232 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005233 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005234 }
5235 ret = 0;
5236 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005237 if (ret == -3)
5238 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005239
Daniel Veillard23e73572002-09-19 19:56:43 +00005240#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005241done:
5242 /*
5243 * Deallocate the copy if done, and free up the validation stack
5244 */
5245 while (repl != NULL) {
5246 tmp = repl->next;
5247 xmlFree(repl);
5248 repl = tmp;
5249 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005250 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005251 if (ctxt->vstateTab != NULL) {
5252 xmlFree(ctxt->vstateTab);
5253 ctxt->vstateTab = NULL;
5254 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005255#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005256 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005257 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005258 if (ctxt->nodeTab != NULL) {
5259 xmlFree(ctxt->nodeTab);
5260 ctxt->nodeTab = NULL;
5261 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005262 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005263
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005264}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005265
Owen Taylor3473f882001-02-23 17:55:21 +00005266/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005267 * xmlValidateCdataElement:
5268 * @ctxt: the validation context
5269 * @doc: a document instance
5270 * @elem: an element instance
5271 *
5272 * Check that an element follows #CDATA
5273 *
5274 * returns 1 if valid or 0 otherwise
5275 */
5276static int
5277xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5278 xmlNodePtr elem) {
5279 int ret = 1;
5280 xmlNodePtr cur, child;
5281
Daniel Veillardceb09b92002-10-04 11:46:37 +00005282 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005283 return(0);
5284
5285 child = elem->children;
5286
5287 cur = child;
5288 while (cur != NULL) {
5289 switch (cur->type) {
5290 case XML_ENTITY_REF_NODE:
5291 /*
5292 * Push the current node to be able to roll back
5293 * and process within the entity
5294 */
5295 if ((cur->children != NULL) &&
5296 (cur->children->children != NULL)) {
5297 nodeVPush(ctxt, cur);
5298 cur = cur->children->children;
5299 continue;
5300 }
5301 break;
5302 case XML_COMMENT_NODE:
5303 case XML_PI_NODE:
5304 case XML_TEXT_NODE:
5305 case XML_CDATA_SECTION_NODE:
5306 break;
5307 default:
5308 ret = 0;
5309 goto done;
5310 }
5311 /*
5312 * Switch to next element
5313 */
5314 cur = cur->next;
5315 while (cur == NULL) {
5316 cur = nodeVPop(ctxt);
5317 if (cur == NULL)
5318 break;
5319 cur = cur->next;
5320 }
5321 }
5322done:
5323 ctxt->nodeMax = 0;
5324 ctxt->nodeNr = 0;
5325 if (ctxt->nodeTab != NULL) {
5326 xmlFree(ctxt->nodeTab);
5327 ctxt->nodeTab = NULL;
5328 }
5329 return(ret);
5330}
5331
5332/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005333 * xmlValidateCheckMixed:
5334 * @ctxt: the validation context
5335 * @cont: the mixed content model
5336 * @qname: the qualified name as appearing in the serialization
5337 *
5338 * Check if the given node is part of the content model.
5339 *
5340 * Returns 1 if yes, 0 if no, -1 in case of error
5341 */
5342static int
William M. Brackedb65a72004-02-06 07:36:04 +00005343xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005344 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005345 const xmlChar *name;
5346 int plen;
5347 name = xmlSplitQName3(qname, &plen);
5348
5349 if (name == NULL) {
5350 while (cont != NULL) {
5351 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5352 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5353 return(1);
5354 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5355 (cont->c1 != NULL) &&
5356 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5357 if ((cont->c1->prefix == NULL) &&
5358 (xmlStrEqual(cont->c1->name, qname)))
5359 return(1);
5360 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5361 (cont->c1 == NULL) ||
5362 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005363 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5364 "Internal: MIXED struct corrupted\n",
5365 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005366 break;
5367 }
5368 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005369 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005370 } else {
5371 while (cont != NULL) {
5372 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5373 if ((cont->prefix != NULL) &&
5374 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5375 (xmlStrEqual(cont->name, name)))
5376 return(1);
5377 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5378 (cont->c1 != NULL) &&
5379 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5380 if ((cont->c1->prefix != NULL) &&
5381 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5382 (xmlStrEqual(cont->c1->name, name)))
5383 return(1);
5384 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5385 (cont->c1 == NULL) ||
5386 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005387 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5388 "Internal: MIXED struct corrupted\n",
5389 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005390 break;
5391 }
5392 cont = cont->c2;
5393 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005394 }
5395 return(0);
5396}
5397
5398/**
5399 * xmlValidGetElemDecl:
5400 * @ctxt: the validation context
5401 * @doc: a document instance
5402 * @elem: an element instance
5403 * @extsubset: pointer, (out) indicate if the declaration was found
5404 * in the external subset.
5405 *
5406 * Finds a declaration associated to an element in the document.
5407 *
5408 * returns the pointer to the declaration or NULL if not found.
5409 */
5410static xmlElementPtr
5411xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5412 xmlNodePtr elem, int *extsubset) {
5413 xmlElementPtr elemDecl = NULL;
5414 const xmlChar *prefix = NULL;
5415
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005416 if ((ctxt == NULL) || (doc == NULL) ||
5417 (elem == NULL) || (elem->name == NULL))
5418 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005419 if (extsubset != NULL)
5420 *extsubset = 0;
5421
5422 /*
5423 * Fetch the declaration for the qualified name
5424 */
5425 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5426 prefix = elem->ns->prefix;
5427
5428 if (prefix != NULL) {
5429 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5430 elem->name, prefix);
5431 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5432 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5433 elem->name, prefix);
5434 if ((elemDecl != NULL) && (extsubset != NULL))
5435 *extsubset = 1;
5436 }
5437 }
5438
5439 /*
5440 * Fetch the declaration for the non qualified name
5441 * This is "non-strict" validation should be done on the
5442 * full QName but in that case being flexible makes sense.
5443 */
5444 if (elemDecl == NULL) {
5445 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5446 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5447 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5448 if ((elemDecl != NULL) && (extsubset != NULL))
5449 *extsubset = 1;
5450 }
5451 }
5452 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005453 xmlErrValidNode(ctxt, elem,
5454 XML_DTD_UNKNOWN_ELEM,
5455 "No declaration for element %s\n",
5456 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005457 }
5458 return(elemDecl);
5459}
5460
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005461#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005462/**
5463 * xmlValidatePushElement:
5464 * @ctxt: the validation context
5465 * @doc: a document instance
5466 * @elem: an element instance
5467 * @qname: the qualified name as appearing in the serialization
5468 *
5469 * Push a new element start on the validation stack.
5470 *
5471 * returns 1 if no validation problem was found or 0 otherwise
5472 */
5473int
5474xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5475 xmlNodePtr elem, const xmlChar *qname) {
5476 int ret = 1;
5477 xmlElementPtr eDecl;
5478 int extsubset = 0;
5479
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005480 if (ctxt == NULL)
5481 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005482/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005483 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5484 xmlValidStatePtr state = ctxt->vstate;
5485 xmlElementPtr elemDecl;
5486
5487 /*
5488 * Check the new element agaisnt the content model of the new elem.
5489 */
5490 if (state->elemDecl != NULL) {
5491 elemDecl = state->elemDecl;
5492
5493 switch(elemDecl->etype) {
5494 case XML_ELEMENT_TYPE_UNDEFINED:
5495 ret = 0;
5496 break;
5497 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005498 xmlErrValidNode(ctxt, state->node,
5499 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005500 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005501 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005502 ret = 0;
5503 break;
5504 case XML_ELEMENT_TYPE_ANY:
5505 /* I don't think anything is required then */
5506 break;
5507 case XML_ELEMENT_TYPE_MIXED:
5508 /* simple case of declared as #PCDATA */
5509 if ((elemDecl->content != NULL) &&
5510 (elemDecl->content->type ==
5511 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005512 xmlErrValidNode(ctxt, state->node,
5513 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005514 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005515 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005516 ret = 0;
5517 } else {
5518 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5519 qname);
5520 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005521 xmlErrValidNode(ctxt, state->node,
5522 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005523 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005524 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005525 }
5526 }
5527 break;
5528 case XML_ELEMENT_TYPE_ELEMENT:
5529 /*
5530 * TODO:
5531 * VC: Standalone Document Declaration
5532 * - element types with element content, if white space
5533 * occurs directly within any instance of those types.
5534 */
5535 if (state->exec != NULL) {
5536 ret = xmlRegExecPushString(state->exec, qname, NULL);
5537 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005538 xmlErrValidNode(ctxt, state->node,
5539 XML_DTD_CONTENT_MODEL,
5540 "Element %s content does not follow the DTD, Misplaced %s\n",
5541 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005542 ret = 0;
5543 } else {
5544 ret = 1;
5545 }
5546 }
5547 break;
5548 }
5549 }
5550 }
5551 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5552 vstateVPush(ctxt, eDecl, elem);
5553 return(ret);
5554}
5555
5556/**
5557 * xmlValidatePushCData:
5558 * @ctxt: the validation context
5559 * @data: some character data read
5560 * @len: the lenght of the data
5561 *
5562 * check the CData parsed for validation in the current stack
5563 *
5564 * returns 1 if no validation problem was found or 0 otherwise
5565 */
5566int
5567xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5568 int ret = 1;
5569
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005570/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005571 if (ctxt == NULL)
5572 return(0);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005573 if (len <= 0)
5574 return(ret);
5575 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5576 xmlValidStatePtr state = ctxt->vstate;
5577 xmlElementPtr elemDecl;
5578
5579 /*
5580 * Check the new element agaisnt the content model of the new elem.
5581 */
5582 if (state->elemDecl != NULL) {
5583 elemDecl = state->elemDecl;
5584
5585 switch(elemDecl->etype) {
5586 case XML_ELEMENT_TYPE_UNDEFINED:
5587 ret = 0;
5588 break;
5589 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005590 xmlErrValidNode(ctxt, state->node,
5591 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005592 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005593 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005594 ret = 0;
5595 break;
5596 case XML_ELEMENT_TYPE_ANY:
5597 break;
5598 case XML_ELEMENT_TYPE_MIXED:
5599 break;
5600 case XML_ELEMENT_TYPE_ELEMENT:
5601 if (len > 0) {
5602 int i;
5603
5604 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005605 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005606 xmlErrValidNode(ctxt, state->node,
5607 XML_DTD_CONTENT_MODEL,
5608 "Element %s content does not follow the DTD, Text not allowed\n",
5609 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005610 ret = 0;
5611 goto done;
5612 }
5613 }
5614 /*
5615 * TODO:
5616 * VC: Standalone Document Declaration
5617 * element types with element content, if white space
5618 * occurs directly within any instance of those types.
5619 */
5620 }
5621 break;
5622 }
5623 }
5624 }
5625done:
5626 return(ret);
5627}
5628
5629/**
5630 * xmlValidatePopElement:
5631 * @ctxt: the validation context
5632 * @doc: a document instance
5633 * @elem: an element instance
5634 * @qname: the qualified name as appearing in the serialization
5635 *
5636 * Pop the element end from the validation stack.
5637 *
5638 * returns 1 if no validation problem was found or 0 otherwise
5639 */
5640int
5641xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005642 xmlNodePtr elem ATTRIBUTE_UNUSED,
5643 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005644 int ret = 1;
5645
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005646 if (ctxt == NULL)
5647 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005648/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005649 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5650 xmlValidStatePtr state = ctxt->vstate;
5651 xmlElementPtr elemDecl;
5652
5653 /*
5654 * Check the new element agaisnt the content model of the new elem.
5655 */
5656 if (state->elemDecl != NULL) {
5657 elemDecl = state->elemDecl;
5658
5659 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5660 if (state->exec != NULL) {
5661 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5662 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005663 xmlErrValidNode(ctxt, state->node,
5664 XML_DTD_CONTENT_MODEL,
5665 "Element %s content does not follow the DTD, Expecting more child\n",
5666 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005667 } else {
5668 /*
5669 * previous validation errors should not generate
5670 * a new one here
5671 */
5672 ret = 1;
5673 }
5674 }
5675 }
5676 }
5677 vstateVPop(ctxt);
5678 }
5679 return(ret);
5680}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005681#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005682
5683/**
Owen Taylor3473f882001-02-23 17:55:21 +00005684 * xmlValidateOneElement:
5685 * @ctxt: the validation context
5686 * @doc: a document instance
5687 * @elem: an element instance
5688 *
5689 * Try to validate a single element and it's attributes,
5690 * basically it does the following checks as described by the
5691 * XML-1.0 recommendation:
5692 * - [ VC: Element Valid ]
5693 * - [ VC: Required Attribute ]
5694 * Then call xmlValidateOneAttribute() for each attribute present.
5695 *
5696 * The ID/IDREF checkings are done separately
5697 *
5698 * returns 1 if valid or 0 otherwise
5699 */
5700
5701int
5702xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5703 xmlNodePtr elem) {
5704 xmlElementPtr elemDecl = NULL;
5705 xmlElementContentPtr cont;
5706 xmlAttributePtr attr;
5707 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005708 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005709 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005710 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005711
5712 CHECK_DTD;
5713
5714 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005715 switch (elem->type) {
5716 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005717 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5718 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005719 return(0);
5720 case XML_TEXT_NODE:
5721 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005722 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5723 "Text element has children !\n",
5724 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005725 return(0);
5726 }
5727 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005728 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5729 "Text element has attribute !\n",
5730 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005731 return(0);
5732 }
5733 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005734 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5735 "Text element has namespace !\n",
5736 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005737 return(0);
5738 }
5739 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005740 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5741 "Text element has namespace !\n",
5742 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005743 return(0);
5744 }
5745 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005746 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5747 "Text element has no content !\n",
5748 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005749 return(0);
5750 }
5751 return(1);
5752 case XML_XINCLUDE_START:
5753 case XML_XINCLUDE_END:
5754 return(1);
5755 case XML_CDATA_SECTION_NODE:
5756 case XML_ENTITY_REF_NODE:
5757 case XML_PI_NODE:
5758 case XML_COMMENT_NODE:
5759 return(1);
5760 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005761 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5762 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005763 return(0);
5764 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005765 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5766 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005767 return(0);
5768 case XML_DOCUMENT_NODE:
5769 case XML_DOCUMENT_TYPE_NODE:
5770 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005771 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5772 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005773 return(0);
5774 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005775 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5776 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005777 return(0);
5778 case XML_ELEMENT_NODE:
5779 break;
5780 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005781 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5782 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005783 return(0);
5784 }
Owen Taylor3473f882001-02-23 17:55:21 +00005785
5786 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005787 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005788 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005789 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5790 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005791 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005792
Daniel Veillardea7751d2002-12-20 00:16:24 +00005793 /*
5794 * If vstateNr is not zero that means continuous validation is
5795 * activated, do not try to check the content model at that level.
5796 */
5797 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005798 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005799 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005800 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005801 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5802 "No declaration for element %s\n",
5803 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005804 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005805 case XML_ELEMENT_TYPE_EMPTY:
5806 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005807 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005808 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005809 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005810 ret = 0;
5811 }
5812 break;
5813 case XML_ELEMENT_TYPE_ANY:
5814 /* I don't think anything is required then */
5815 break;
5816 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005817
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005818 /* simple case of declared as #PCDATA */
5819 if ((elemDecl->content != NULL) &&
5820 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5821 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5822 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005823 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005824 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005825 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005826 }
5827 break;
5828 }
Owen Taylor3473f882001-02-23 17:55:21 +00005829 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005830 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005831 while (child != NULL) {
5832 if (child->type == XML_ELEMENT_NODE) {
5833 name = child->name;
5834 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005835 xmlChar fn[50];
5836 xmlChar *fullname;
5837
5838 fullname = xmlBuildQName(child->name, child->ns->prefix,
5839 fn, 50);
5840 if (fullname == NULL)
5841 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005842 cont = elemDecl->content;
5843 while (cont != NULL) {
5844 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005845 if (xmlStrEqual(cont->name, fullname))
5846 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005847 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5848 (cont->c1 != NULL) &&
5849 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005850 if (xmlStrEqual(cont->c1->name, fullname))
5851 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005852 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5853 (cont->c1 == NULL) ||
5854 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005855 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5856 "Internal: MIXED struct corrupted\n",
5857 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005858 break;
5859 }
5860 cont = cont->c2;
5861 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005862 if ((fullname != fn) && (fullname != child->name))
5863 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005864 if (cont != NULL)
5865 goto child_ok;
5866 }
5867 cont = elemDecl->content;
5868 while (cont != NULL) {
5869 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5870 if (xmlStrEqual(cont->name, name)) break;
5871 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5872 (cont->c1 != NULL) &&
5873 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5874 if (xmlStrEqual(cont->c1->name, name)) break;
5875 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5876 (cont->c1 == NULL) ||
5877 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005878 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5879 "Internal: MIXED struct corrupted\n",
5880 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005881 break;
5882 }
5883 cont = cont->c2;
5884 }
5885 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005886 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00005887 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005888 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005889 ret = 0;
5890 }
5891 }
5892child_ok:
5893 child = child->next;
5894 }
5895 break;
5896 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005897 if ((doc->standalone == 1) && (extsubset == 1)) {
5898 /*
5899 * VC: Standalone Document Declaration
5900 * - element types with element content, if white space
5901 * occurs directly within any instance of those types.
5902 */
5903 child = elem->children;
5904 while (child != NULL) {
5905 if (child->type == XML_TEXT_NODE) {
5906 const xmlChar *content = child->content;
5907
William M. Brack76e95df2003-10-18 16:20:14 +00005908 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005909 content++;
5910 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005911 xmlErrValidNode(ctxt, elem,
5912 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005913"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005914 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005915 ret = 0;
5916 break;
5917 }
5918 }
5919 child =child->next;
5920 }
5921 }
Owen Taylor3473f882001-02-23 17:55:21 +00005922 child = elem->children;
5923 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005924 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005925 if (tmp <= 0)
5926 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005927 break;
5928 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005929 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00005930
5931 /* [ VC: Required Attribute ] */
5932 attr = elemDecl->attributes;
5933 while (attr != NULL) {
5934 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005935 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005936
Daniel Veillarde4301c82002-02-13 13:32:35 +00005937 if ((attr->prefix == NULL) &&
5938 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5939 xmlNsPtr ns;
5940
5941 ns = elem->nsDef;
5942 while (ns != NULL) {
5943 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005944 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005945 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00005946 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005947 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5948 xmlNsPtr ns;
5949
5950 ns = elem->nsDef;
5951 while (ns != NULL) {
5952 if (xmlStrEqual(attr->name, ns->prefix))
5953 goto found;
5954 ns = ns->next;
5955 }
5956 } else {
5957 xmlAttrPtr attrib;
5958
5959 attrib = elem->properties;
5960 while (attrib != NULL) {
5961 if (xmlStrEqual(attrib->name, attr->name)) {
5962 if (attr->prefix != NULL) {
5963 xmlNsPtr nameSpace = attrib->ns;
5964
5965 if (nameSpace == NULL)
5966 nameSpace = elem->ns;
5967 /*
5968 * qualified names handling is problematic, having a
5969 * different prefix should be possible but DTDs don't
5970 * allow to define the URI instead of the prefix :-(
5971 */
5972 if (nameSpace == NULL) {
5973 if (qualified < 0)
5974 qualified = 0;
5975 } else if (!xmlStrEqual(nameSpace->prefix,
5976 attr->prefix)) {
5977 if (qualified < 1)
5978 qualified = 1;
5979 } else
5980 goto found;
5981 } else {
5982 /*
5983 * We should allow applications to define namespaces
5984 * for their application even if the DTD doesn't
5985 * carry one, otherwise, basically we would always
5986 * break.
5987 */
5988 goto found;
5989 }
5990 }
5991 attrib = attrib->next;
5992 }
Owen Taylor3473f882001-02-23 17:55:21 +00005993 }
5994 if (qualified == -1) {
5995 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005996 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005997 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005998 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005999 ret = 0;
6000 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006001 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006002 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00006003 elem->name, attr->prefix,attr->name);
6004 ret = 0;
6005 }
6006 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006007 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006008 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006009 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006010 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006011 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006012 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006013 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006014 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006015 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
6016 /*
6017 * Special tests checking #FIXED namespace declarations
6018 * have the right value since this is not done as an
6019 * attribute checking
6020 */
6021 if ((attr->prefix == NULL) &&
6022 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6023 xmlNsPtr ns;
6024
6025 ns = elem->nsDef;
6026 while (ns != NULL) {
6027 if (ns->prefix == NULL) {
6028 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006029 xmlErrValidNode(ctxt, elem,
6030 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00006031 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006032 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006033 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006034 }
6035 goto found;
6036 }
6037 ns = ns->next;
6038 }
6039 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6040 xmlNsPtr ns;
6041
6042 ns = elem->nsDef;
6043 while (ns != NULL) {
6044 if (xmlStrEqual(attr->name, ns->prefix)) {
6045 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006046 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006047 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006048 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006049 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006050 }
6051 goto found;
6052 }
6053 ns = ns->next;
6054 }
6055 }
Owen Taylor3473f882001-02-23 17:55:21 +00006056 }
6057found:
6058 attr = attr->nexth;
6059 }
6060 return(ret);
6061}
6062
6063/**
6064 * xmlValidateRoot:
6065 * @ctxt: the validation context
6066 * @doc: a document instance
6067 *
6068 * Try to validate a the root element
6069 * basically it does the following check as described by the
6070 * XML-1.0 recommendation:
6071 * - [ VC: Root Element Type ]
6072 * it doesn't try to recurse or apply other check to the element
6073 *
6074 * returns 1 if valid or 0 otherwise
6075 */
6076
6077int
6078xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6079 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006080 int ret;
6081
Owen Taylor3473f882001-02-23 17:55:21 +00006082 if (doc == NULL) return(0);
6083
6084 root = xmlDocGetRootElement(doc);
6085 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006086 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6087 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006088 return(0);
6089 }
6090
6091 /*
6092 * When doing post validation against a separate DTD, those may
6093 * no internal subset has been generated
6094 */
6095 if ((doc->intSubset != NULL) &&
6096 (doc->intSubset->name != NULL)) {
6097 /*
6098 * Check first the document root against the NQName
6099 */
6100 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6101 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006102 xmlChar fn[50];
6103 xmlChar *fullname;
6104
6105 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6106 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006107 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006108 return(0);
6109 }
6110 ret = xmlStrEqual(doc->intSubset->name, fullname);
6111 if ((fullname != fn) && (fullname != root->name))
6112 xmlFree(fullname);
6113 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006114 goto name_ok;
6115 }
6116 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6117 (xmlStrEqual(root->name, BAD_CAST "html")))
6118 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006119 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6120 "root and DTD name do not match '%s' and '%s'\n",
6121 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006122 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006123 }
6124 }
6125name_ok:
6126 return(1);
6127}
6128
6129
6130/**
6131 * xmlValidateElement:
6132 * @ctxt: the validation context
6133 * @doc: a document instance
6134 * @elem: an element instance
6135 *
6136 * Try to validate the subtree under an element
6137 *
6138 * returns 1 if valid or 0 otherwise
6139 */
6140
6141int
6142xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6143 xmlNodePtr child;
6144 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006145 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006146 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006147 int ret = 1;
6148
6149 if (elem == NULL) return(0);
6150
6151 /*
6152 * XInclude elements were added after parsing in the infoset,
6153 * they don't really mean anything validation wise.
6154 */
6155 if ((elem->type == XML_XINCLUDE_START) ||
6156 (elem->type == XML_XINCLUDE_END))
6157 return(1);
6158
6159 CHECK_DTD;
6160
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006161 /*
6162 * Entities references have to be handled separately
6163 */
6164 if (elem->type == XML_ENTITY_REF_NODE) {
6165 return(1);
6166 }
6167
Owen Taylor3473f882001-02-23 17:55:21 +00006168 ret &= xmlValidateOneElement(ctxt, doc, elem);
6169 attr = elem->properties;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006170 while (attr != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006171 value = xmlNodeListGetString(doc, attr->children, 0);
6172 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6173 if (value != NULL)
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006174 xmlFree((char *)value);
Owen Taylor3473f882001-02-23 17:55:21 +00006175 attr= attr->next;
6176 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006177 ns = elem->nsDef;
6178 while (ns != NULL) {
Daniel Veillard1f5c9892003-12-29 17:09:55 +00006179 if (elem->ns == NULL)
6180 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6181 ns, ns->href);
6182 else
6183 ret &= xmlValidateOneNamespace(ctxt, doc, elem, elem->ns->prefix,
6184 ns, ns->href);
Daniel Veillarde133dd82003-10-30 10:42:20 +00006185 ns = ns->next;
6186 }
Owen Taylor3473f882001-02-23 17:55:21 +00006187 child = elem->children;
6188 while (child != NULL) {
6189 ret &= xmlValidateElement(ctxt, doc, child);
6190 child = child->next;
6191 }
6192
6193 return(ret);
6194}
6195
Daniel Veillard8730c562001-02-26 10:49:57 +00006196/**
6197 * xmlValidateRef:
6198 * @ref: A reference to be validated
6199 * @ctxt: Validation context
6200 * @name: Name of ID we are searching for
6201 *
6202 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006203static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006204xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006205 const xmlChar *name) {
6206 xmlAttrPtr id;
6207 xmlAttrPtr attr;
6208
6209 if (ref == NULL)
6210 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006211 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006212 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006213 attr = ref->attr;
6214 if (attr == NULL) {
6215 xmlChar *dup, *str = NULL, *cur, save;
6216
6217 dup = xmlStrdup(name);
6218 if (dup == NULL) {
6219 ctxt->valid = 0;
6220 return;
6221 }
6222 cur = dup;
6223 while (*cur != 0) {
6224 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006225 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006226 save = *cur;
6227 *cur = 0;
6228 id = xmlGetID(ctxt->doc, str);
6229 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006230 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006231 "attribute %s line %d references an unknown ID \"%s\"\n",
6232 ref->name, ref->lineno, str);
6233 ctxt->valid = 0;
6234 }
6235 if (save == 0)
6236 break;
6237 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006238 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006239 }
6240 xmlFree(dup);
6241 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006242 id = xmlGetID(ctxt->doc, name);
6243 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006244 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006245 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006246 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006247 ctxt->valid = 0;
6248 }
6249 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6250 xmlChar *dup, *str = NULL, *cur, save;
6251
6252 dup = xmlStrdup(name);
6253 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006254 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006255 ctxt->valid = 0;
6256 return;
6257 }
6258 cur = dup;
6259 while (*cur != 0) {
6260 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006261 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006262 save = *cur;
6263 *cur = 0;
6264 id = xmlGetID(ctxt->doc, str);
6265 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006266 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006267 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006268 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006269 ctxt->valid = 0;
6270 }
6271 if (save == 0)
6272 break;
6273 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006274 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006275 }
6276 xmlFree(dup);
6277 }
6278}
6279
6280/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006281 * xmlWalkValidateList:
6282 * @data: Contents of current link
6283 * @user: Value supplied by the user
6284 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006285 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006286 */
6287static int
6288xmlWalkValidateList(const void *data, const void *user)
6289{
6290 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6291 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6292 return 1;
6293}
6294
6295/**
6296 * xmlValidateCheckRefCallback:
6297 * @ref_list: List of references
6298 * @ctxt: Validation context
6299 * @name: Name of ID we are searching for
6300 *
6301 */
6302static void
6303xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6304 const xmlChar *name) {
6305 xmlValidateMemo memo;
6306
6307 if (ref_list == NULL)
6308 return;
6309 memo.ctxt = ctxt;
6310 memo.name = name;
6311
6312 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6313
6314}
6315
6316/**
Owen Taylor3473f882001-02-23 17:55:21 +00006317 * xmlValidateDocumentFinal:
6318 * @ctxt: the validation context
6319 * @doc: a document instance
6320 *
6321 * Does the final step for the document validation once all the
6322 * incremental validation steps have been completed
6323 *
6324 * basically it does the following checks described by the XML Rec
6325 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006326 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006327 *
6328 * returns 1 if valid or 0 otherwise
6329 */
6330
6331int
6332xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6333 xmlRefTablePtr table;
6334
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006335 if (ctxt == NULL)
6336 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006337 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006338 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6339 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006340 return(0);
6341 }
6342
6343 /*
6344 * Check all the NOTATION/NOTATIONS attributes
6345 */
6346 /*
6347 * Check all the ENTITY/ENTITIES attributes definition for validity
6348 */
6349 /*
6350 * Check all the IDREF/IDREFS attributes definition for validity
6351 */
6352 table = (xmlRefTablePtr) doc->refs;
6353 ctxt->doc = doc;
6354 ctxt->valid = 1;
6355 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6356 return(ctxt->valid);
6357}
6358
6359/**
6360 * xmlValidateDtd:
6361 * @ctxt: the validation context
6362 * @doc: a document instance
6363 * @dtd: a dtd instance
6364 *
6365 * Try to validate the document against the dtd instance
6366 *
William M. Brack367df6e2004-10-23 18:14:36 +00006367 * Basically it does check all the definitions in the DtD.
6368 * Note the the internal subset (if present) is de-coupled
6369 * (i.e. not used), which could give problems if ID or IDREF
6370 * is present.
Owen Taylor3473f882001-02-23 17:55:21 +00006371 *
6372 * returns 1 if valid or 0 otherwise
6373 */
6374
6375int
6376xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6377 int ret;
William M. Brack367df6e2004-10-23 18:14:36 +00006378 xmlDtdPtr oldExt, oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006379 xmlNodePtr root;
6380
6381 if (dtd == NULL) return(0);
6382 if (doc == NULL) return(0);
6383 oldExt = doc->extSubset;
William M. Brack367df6e2004-10-23 18:14:36 +00006384 oldInt = doc->intSubset;
Owen Taylor3473f882001-02-23 17:55:21 +00006385 doc->extSubset = dtd;
William M. Brack367df6e2004-10-23 18:14:36 +00006386 doc->intSubset = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006387 ret = xmlValidateRoot(ctxt, doc);
6388 if (ret == 0) {
6389 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006390 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006391 return(ret);
6392 }
6393 if (doc->ids != NULL) {
6394 xmlFreeIDTable(doc->ids);
6395 doc->ids = NULL;
6396 }
6397 if (doc->refs != NULL) {
6398 xmlFreeRefTable(doc->refs);
6399 doc->refs = NULL;
6400 }
6401 root = xmlDocGetRootElement(doc);
6402 ret = xmlValidateElement(ctxt, doc, root);
6403 ret &= xmlValidateDocumentFinal(ctxt, doc);
6404 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006405 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006406 return(ret);
6407}
6408
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006409static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006410xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6411 const xmlChar *name ATTRIBUTE_UNUSED) {
6412 if (cur == NULL)
6413 return;
6414 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6415 xmlChar *notation = cur->content;
6416
Daniel Veillard878eab02002-02-19 13:46:09 +00006417 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006418 int ret;
6419
6420 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6421 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006422 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006423 }
6424 }
6425 }
6426}
6427
6428static void
Owen Taylor3473f882001-02-23 17:55:21 +00006429xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006430 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006431 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006432 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006433 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006434
Owen Taylor3473f882001-02-23 17:55:21 +00006435 if (cur == NULL)
6436 return;
6437 switch (cur->atype) {
6438 case XML_ATTRIBUTE_CDATA:
6439 case XML_ATTRIBUTE_ID:
6440 case XML_ATTRIBUTE_IDREF :
6441 case XML_ATTRIBUTE_IDREFS:
6442 case XML_ATTRIBUTE_NMTOKEN:
6443 case XML_ATTRIBUTE_NMTOKENS:
6444 case XML_ATTRIBUTE_ENUMERATION:
6445 break;
6446 case XML_ATTRIBUTE_ENTITY:
6447 case XML_ATTRIBUTE_ENTITIES:
6448 case XML_ATTRIBUTE_NOTATION:
6449 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006450
6451 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6452 cur->atype, cur->defaultValue);
6453 if ((ret == 0) && (ctxt->valid == 1))
6454 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006455 }
6456 if (cur->tree != NULL) {
6457 xmlEnumerationPtr tree = cur->tree;
6458 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006459 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006460 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006461 if ((ret == 0) && (ctxt->valid == 1))
6462 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006463 tree = tree->next;
6464 }
6465 }
6466 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006467 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6468 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006469 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006470 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006471 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006472 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006473 return;
6474 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006475
6476 if (doc != NULL)
6477 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6478 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006479 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006480 if ((elem == NULL) && (cur->parent != NULL) &&
6481 (cur->parent->type == XML_DTD_NODE))
6482 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006483 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006484 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006485 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006486 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006487 return;
6488 }
6489 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006490 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006491 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006492 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006493 ctxt->valid = 0;
6494 }
6495 }
Owen Taylor3473f882001-02-23 17:55:21 +00006496}
6497
6498/**
6499 * xmlValidateDtdFinal:
6500 * @ctxt: the validation context
6501 * @doc: a document instance
6502 *
6503 * Does the final step for the dtds validation once all the
6504 * subsets have been parsed
6505 *
6506 * basically it does the following checks described by the XML Rec
6507 * - check that ENTITY and ENTITIES type attributes default or
6508 * possible values matches one of the defined entities.
6509 * - check that NOTATION type attributes default or
6510 * possible values matches one of the defined notations.
6511 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006512 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006513 */
6514
6515int
6516xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006517 xmlDtdPtr dtd;
6518 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006519 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006520
6521 if (doc == NULL) return(0);
6522 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6523 return(0);
6524 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006525 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006526 dtd = doc->intSubset;
6527 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6528 table = (xmlAttributeTablePtr) dtd->attributes;
6529 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006530 }
6531 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006532 entities = (xmlEntitiesTablePtr) dtd->entities;
6533 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6534 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006535 }
6536 dtd = doc->extSubset;
6537 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6538 table = (xmlAttributeTablePtr) dtd->attributes;
6539 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006540 }
6541 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006542 entities = (xmlEntitiesTablePtr) dtd->entities;
6543 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6544 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006545 }
6546 return(ctxt->valid);
6547}
6548
6549/**
6550 * xmlValidateDocument:
6551 * @ctxt: the validation context
6552 * @doc: a document instance
6553 *
6554 * Try to validate the document instance
6555 *
6556 * basically it does the all the checks described by the XML Rec
6557 * i.e. validates the internal and external subset (if present)
6558 * and validate the document tree.
6559 *
6560 * returns 1 if valid or 0 otherwise
6561 */
6562
6563int
6564xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6565 int ret;
6566 xmlNodePtr root;
6567
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006568 if (doc == NULL)
6569 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006570 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006571 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6572 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006573 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006574 }
Owen Taylor3473f882001-02-23 17:55:21 +00006575 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6576 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
William M. Brack8c22f9f2004-08-06 16:23:27 +00006577 xmlChar *sysID;
6578 if (doc->intSubset->SystemID != NULL) {
William M. Brackbebe7302004-08-05 06:46:47 +00006579 sysID = xmlBuildURI(doc->intSubset->SystemID,
6580 doc->URL);
William M. Brack8c22f9f2004-08-06 16:23:27 +00006581 if (sysID == NULL) {
6582 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6583 "Could not build URI for external subset \"%s\"\n",
6584 (const char *) doc->intSubset->SystemID);
6585 return 0;
6586 }
6587 } else
William M. Brackbebe7302004-08-05 06:46:47 +00006588 sysID = NULL;
William M. Brack8c22f9f2004-08-06 16:23:27 +00006589 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
William M. Brackbebe7302004-08-05 06:46:47 +00006590 (const xmlChar *)sysID);
William M. Brackbebe7302004-08-05 06:46:47 +00006591 if (sysID != NULL)
6592 xmlFree(sysID);
Owen Taylor3473f882001-02-23 17:55:21 +00006593 if (doc->extSubset == NULL) {
6594 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006595 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006596 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006597 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006598 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006599 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006600 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006601 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006602 }
6603 return(0);
6604 }
6605 }
6606
6607 if (doc->ids != NULL) {
6608 xmlFreeIDTable(doc->ids);
6609 doc->ids = NULL;
6610 }
6611 if (doc->refs != NULL) {
6612 xmlFreeRefTable(doc->refs);
6613 doc->refs = NULL;
6614 }
6615 ret = xmlValidateDtdFinal(ctxt, doc);
6616 if (!xmlValidateRoot(ctxt, doc)) return(0);
6617
6618 root = xmlDocGetRootElement(doc);
6619 ret &= xmlValidateElement(ctxt, doc, root);
6620 ret &= xmlValidateDocumentFinal(ctxt, doc);
6621 return(ret);
6622}
6623
Owen Taylor3473f882001-02-23 17:55:21 +00006624/************************************************************************
6625 * *
6626 * Routines for dynamic validation editing *
6627 * *
6628 ************************************************************************/
6629
6630/**
6631 * xmlValidGetPotentialChildren:
6632 * @ctree: an element content tree
6633 * @list: an array to store the list of child names
6634 * @len: a pointer to the number of element in the list
6635 * @max: the size of the array
6636 *
6637 * Build/extend a list of potential children allowed by the content tree
6638 *
6639 * returns the number of element in the list, or -1 in case of error.
6640 */
6641
6642int
6643xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6644 int *len, int max) {
6645 int i;
6646
6647 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6648 return(-1);
6649 if (*len >= max) return(*len);
6650
6651 switch (ctree->type) {
6652 case XML_ELEMENT_CONTENT_PCDATA:
6653 for (i = 0; i < *len;i++)
6654 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6655 list[(*len)++] = BAD_CAST "#PCDATA";
6656 break;
6657 case XML_ELEMENT_CONTENT_ELEMENT:
6658 for (i = 0; i < *len;i++)
6659 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6660 list[(*len)++] = ctree->name;
6661 break;
6662 case XML_ELEMENT_CONTENT_SEQ:
6663 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6664 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6665 break;
6666 case XML_ELEMENT_CONTENT_OR:
6667 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6668 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6669 break;
6670 }
6671
6672 return(*len);
6673}
6674
William M. Brack9333cc22004-06-24 08:33:40 +00006675/*
6676 * Dummy function to suppress messages while we try out valid elements
6677 */
6678static void xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
6679 const char *msg ATTRIBUTE_UNUSED, ...) {
6680 return;
6681}
6682
Owen Taylor3473f882001-02-23 17:55:21 +00006683/**
6684 * xmlValidGetValidElements:
6685 * @prev: an element to insert after
6686 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006687 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006688 * @max: the size of the array
6689 *
6690 * This function returns the list of authorized children to insert
6691 * within an existing tree while respecting the validity constraints
6692 * forced by the Dtd. The insertion point is defined using @prev and
6693 * @next in the following ways:
6694 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6695 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6696 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6697 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6698 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6699 *
6700 * pointers to the element names are inserted at the beginning of the array
6701 * and do not need to be freed.
6702 *
6703 * returns the number of element in the list, or -1 in case of error. If
6704 * the function returns the value @max the caller is invited to grow the
6705 * receiving array and retry.
6706 */
6707
6708int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006709xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006710 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006711 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006712 int nb_valid_elements = 0;
6713 const xmlChar *elements[256];
6714 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006715 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006716
6717 xmlNode *ref_node;
6718 xmlNode *parent;
6719 xmlNode *test_node;
6720
6721 xmlNode *prev_next;
6722 xmlNode *next_prev;
6723 xmlNode *parent_childs;
6724 xmlNode *parent_last;
6725
6726 xmlElement *element_desc;
6727
6728 if (prev == NULL && next == NULL)
6729 return(-1);
6730
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006731 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006732 if (max <= 0) return(-1);
6733
William M. Brack9333cc22004-06-24 08:33:40 +00006734 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6735 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6736
Owen Taylor3473f882001-02-23 17:55:21 +00006737 nb_valid_elements = 0;
6738 ref_node = prev ? prev : next;
6739 parent = ref_node->parent;
6740
6741 /*
6742 * Retrieves the parent element declaration
6743 */
6744 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6745 parent->name);
6746 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6747 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6748 parent->name);
6749 if (element_desc == NULL) return(-1);
6750
6751 /*
6752 * Do a backup of the current tree structure
6753 */
6754 prev_next = prev ? prev->next : NULL;
6755 next_prev = next ? next->prev : NULL;
6756 parent_childs = parent->children;
6757 parent_last = parent->last;
6758
6759 /*
6760 * Creates a dummy node and insert it into the tree
6761 */
Daniel Veillard95ddcd32004-10-26 21:53:55 +00006762 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006763 test_node->parent = parent;
6764 test_node->prev = prev;
6765 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006766 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006767
6768 if (prev) prev->next = test_node;
6769 else parent->children = test_node;
6770
6771 if (next) next->prev = test_node;
6772 else parent->last = test_node;
6773
6774 /*
6775 * Insert each potential child node and check if the parent is
6776 * still valid
6777 */
6778 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6779 elements, &nb_elements, 256);
6780
6781 for (i = 0;i < nb_elements;i++) {
6782 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006783 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006784 int j;
6785
6786 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006787 if (xmlStrEqual(elements[i], names[j])) break;
6788 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00006789 if (nb_valid_elements >= max) break;
6790 }
6791 }
6792
6793 /*
6794 * Restore the tree structure
6795 */
6796 if (prev) prev->next = prev_next;
6797 if (next) next->prev = next_prev;
6798 parent->children = parent_childs;
6799 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006800
6801 /*
6802 * Free up the dummy node
6803 */
6804 test_node->name = name;
6805 xmlFreeNode(test_node);
6806
Owen Taylor3473f882001-02-23 17:55:21 +00006807 return(nb_valid_elements);
6808}
Daniel Veillard4432df22003-09-28 18:58:27 +00006809#endif /* LIBXML_VALID_ENABLED */
6810