blob: 3884c904c4a27825f3835cd1bbff300d6ae8ff7b [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) {
888 xmlFree(cur);
889}
890
Daniel Veillard4432df22003-09-28 18:58:27 +0000891#endif /* LIBXML_VALID_ENABLED */
892
Daniel Veillarda37aab82003-06-09 09:10:36 +0000893/**
Owen Taylor3473f882001-02-23 17:55:21 +0000894 * xmlNewElementContent:
895 * @name: the subelement name or NULL
896 * @type: the type of element content decl
897 *
898 * Allocate an element content structure.
899 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000900 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000901 */
902xmlElementContentPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000903xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000904 xmlElementContentPtr ret;
905
906 switch(type) {
907 case XML_ELEMENT_CONTENT_ELEMENT:
908 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000909 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
910 "xmlNewElementContent : name == NULL !\n",
911 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000912 }
913 break;
914 case XML_ELEMENT_CONTENT_PCDATA:
915 case XML_ELEMENT_CONTENT_SEQ:
916 case XML_ELEMENT_CONTENT_OR:
917 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000918 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
919 "xmlNewElementContent : name != NULL !\n",
920 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000921 }
922 break;
923 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000924 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
925 "Internal: ELEMENT content corrupted invalid type\n",
926 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000927 return(NULL);
928 }
929 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
930 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000931 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000932 return(NULL);
933 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000934 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000935 ret->type = type;
936 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000937 if (name != NULL) {
938 xmlChar *prefix = NULL;
939 ret->name = xmlSplitQName2(name, &prefix);
940 if (ret->name == NULL)
941 ret->name = xmlStrdup(name);
942 ret->prefix = prefix;
943 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000944 ret->name = NULL;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000945 ret->prefix = NULL;
946 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000947 ret->c1 = ret->c2 = ret->parent = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000948 return(ret);
949}
950
951/**
952 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000953 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +0000954 *
955 * Build a copy of an element content description.
956 *
957 * Returns the new xmlElementContentPtr or NULL in case of error.
958 */
959xmlElementContentPtr
960xmlCopyElementContent(xmlElementContentPtr cur) {
961 xmlElementContentPtr ret;
962
963 if (cur == NULL) return(NULL);
964 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
965 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000966 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000967 return(NULL);
968 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000969 if (cur->prefix != NULL)
970 ret->prefix = xmlStrdup(cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000971 ret->ocur = cur->ocur;
972 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000973 if (ret->c1 != NULL)
974 ret->c1->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000975 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000976 if (ret->c2 != NULL)
977 ret->c2->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000978 return(ret);
979}
980
981/**
982 * xmlFreeElementContent:
983 * @cur: the element content tree to free
984 *
985 * Free an element content structure. This is a recursive call !
986 */
987void
988xmlFreeElementContent(xmlElementContentPtr cur) {
989 if (cur == NULL) return;
990 switch (cur->type) {
991 case XML_ELEMENT_CONTENT_PCDATA:
992 case XML_ELEMENT_CONTENT_ELEMENT:
993 case XML_ELEMENT_CONTENT_SEQ:
994 case XML_ELEMENT_CONTENT_OR:
995 break;
996 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000997 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
998 "Internal: ELEMENT content corrupted invalid type\n",
999 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001000 return;
1001 }
1002 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
1003 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
1004 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001005 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001006 xmlFree(cur);
1007}
1008
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001009#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001010/**
1011 * xmlDumpElementContent:
1012 * @buf: An XML buffer
1013 * @content: An element table
1014 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1015 *
1016 * This will dump the content of the element table as an XML DTD definition
1017 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001018static void
Owen Taylor3473f882001-02-23 17:55:21 +00001019xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1020 if (content == NULL) return;
1021
1022 if (glob) xmlBufferWriteChar(buf, "(");
1023 switch (content->type) {
1024 case XML_ELEMENT_CONTENT_PCDATA:
1025 xmlBufferWriteChar(buf, "#PCDATA");
1026 break;
1027 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001028 if (content->prefix != NULL) {
1029 xmlBufferWriteCHAR(buf, content->prefix);
1030 xmlBufferWriteChar(buf, ":");
1031 }
Owen Taylor3473f882001-02-23 17:55:21 +00001032 xmlBufferWriteCHAR(buf, content->name);
1033 break;
1034 case XML_ELEMENT_CONTENT_SEQ:
1035 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1036 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1037 xmlDumpElementContent(buf, content->c1, 1);
1038 else
1039 xmlDumpElementContent(buf, content->c1, 0);
1040 xmlBufferWriteChar(buf, " , ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001041 if ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1042 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
1043 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001044 xmlDumpElementContent(buf, content->c2, 1);
1045 else
1046 xmlDumpElementContent(buf, content->c2, 0);
1047 break;
1048 case XML_ELEMENT_CONTENT_OR:
1049 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1050 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1051 xmlDumpElementContent(buf, content->c1, 1);
1052 else
1053 xmlDumpElementContent(buf, content->c1, 0);
1054 xmlBufferWriteChar(buf, " | ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001055 if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1056 ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
1057 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001058 xmlDumpElementContent(buf, content->c2, 1);
1059 else
1060 xmlDumpElementContent(buf, content->c2, 0);
1061 break;
1062 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001063 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1064 "Internal: ELEMENT content corrupted invalid type\n",
1065 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001066 }
1067 if (glob)
1068 xmlBufferWriteChar(buf, ")");
1069 switch (content->ocur) {
1070 case XML_ELEMENT_CONTENT_ONCE:
1071 break;
1072 case XML_ELEMENT_CONTENT_OPT:
1073 xmlBufferWriteChar(buf, "?");
1074 break;
1075 case XML_ELEMENT_CONTENT_MULT:
1076 xmlBufferWriteChar(buf, "*");
1077 break;
1078 case XML_ELEMENT_CONTENT_PLUS:
1079 xmlBufferWriteChar(buf, "+");
1080 break;
1081 }
1082}
1083
1084/**
1085 * xmlSprintfElementContent:
1086 * @buf: an output buffer
1087 * @content: An element table
1088 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1089 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001090 * Deprecated, unsafe, use xmlSnprintfElementContent
1091 */
1092void
1093xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1094 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1095 int glob ATTRIBUTE_UNUSED) {
1096}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001097#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001098
1099/**
1100 * xmlSnprintfElementContent:
1101 * @buf: an output buffer
1102 * @size: the buffer size
1103 * @content: An element table
1104 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1105 *
Owen Taylor3473f882001-02-23 17:55:21 +00001106 * This will dump the content of the element content definition
1107 * Intended just for the debug routine
1108 */
1109void
Daniel Veillardd3d06722001-08-15 12:06:36 +00001110xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int glob) {
1111 int len;
1112
Owen Taylor3473f882001-02-23 17:55:21 +00001113 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001114 len = strlen(buf);
1115 if (size - len < 50) {
1116 if ((size - len > 4) && (buf[len - 1] != '.'))
1117 strcat(buf, " ...");
1118 return;
1119 }
Owen Taylor3473f882001-02-23 17:55:21 +00001120 if (glob) strcat(buf, "(");
1121 switch (content->type) {
1122 case XML_ELEMENT_CONTENT_PCDATA:
1123 strcat(buf, "#PCDATA");
1124 break;
1125 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001126 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001127 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001128 strcat(buf, " ...");
1129 return;
1130 }
1131 strcat(buf, (char *) content->prefix);
1132 strcat(buf, ":");
1133 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001134 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001135 strcat(buf, " ...");
1136 return;
1137 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001138 if (content->name != NULL)
1139 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001140 break;
1141 case XML_ELEMENT_CONTENT_SEQ:
1142 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1143 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001144 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001145 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001146 xmlSnprintfElementContent(buf, size, content->c1, 0);
1147 len = strlen(buf);
1148 if (size - len < 50) {
1149 if ((size - len > 4) && (buf[len - 1] != '.'))
1150 strcat(buf, " ...");
1151 return;
1152 }
Owen Taylor3473f882001-02-23 17:55:21 +00001153 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001154 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1155 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1156 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001157 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001158 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001159 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001160 break;
1161 case XML_ELEMENT_CONTENT_OR:
1162 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1163 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001164 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001165 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001166 xmlSnprintfElementContent(buf, size, content->c1, 0);
1167 len = strlen(buf);
1168 if (size - len < 50) {
1169 if ((size - len > 4) && (buf[len - 1] != '.'))
1170 strcat(buf, " ...");
1171 return;
1172 }
Owen Taylor3473f882001-02-23 17:55:21 +00001173 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001174 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1175 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1176 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001177 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001178 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001179 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001180 break;
1181 }
1182 if (glob)
1183 strcat(buf, ")");
1184 switch (content->ocur) {
1185 case XML_ELEMENT_CONTENT_ONCE:
1186 break;
1187 case XML_ELEMENT_CONTENT_OPT:
1188 strcat(buf, "?");
1189 break;
1190 case XML_ELEMENT_CONTENT_MULT:
1191 strcat(buf, "*");
1192 break;
1193 case XML_ELEMENT_CONTENT_PLUS:
1194 strcat(buf, "+");
1195 break;
1196 }
1197}
1198
1199/****************************************************************
1200 * *
1201 * Registration of DTD declarations *
1202 * *
1203 ****************************************************************/
1204
1205/**
1206 * xmlCreateElementTable:
1207 *
1208 * create and initialize an empty element hash table.
1209 *
1210 * Returns the xmlElementTablePtr just created or NULL in case of error.
1211 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001212static xmlElementTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001213xmlCreateElementTable(void) {
1214 return(xmlHashCreate(0));
1215}
1216
1217/**
1218 * xmlFreeElement:
1219 * @elem: An element
1220 *
1221 * Deallocate the memory used by an element definition
1222 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001223static void
Owen Taylor3473f882001-02-23 17:55:21 +00001224xmlFreeElement(xmlElementPtr elem) {
1225 if (elem == NULL) return;
1226 xmlUnlinkNode((xmlNodePtr) elem);
1227 xmlFreeElementContent(elem->content);
1228 if (elem->name != NULL)
1229 xmlFree((xmlChar *) elem->name);
1230 if (elem->prefix != NULL)
1231 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001232#ifdef LIBXML_REGEXP_ENABLED
1233 if (elem->contModel != NULL)
1234 xmlRegFreeRegexp(elem->contModel);
1235#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001236 xmlFree(elem);
1237}
1238
1239
1240/**
1241 * xmlAddElementDecl:
1242 * @ctxt: the validation context
1243 * @dtd: pointer to the DTD
1244 * @name: the entity name
1245 * @type: the element type
1246 * @content: the element content tree or NULL
1247 *
1248 * Register a new element declaration
1249 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001250 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001251 */
1252xmlElementPtr
William M. Brackedb65a72004-02-06 07:36:04 +00001253xmlAddElementDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001254 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001255 xmlElementTypeVal type,
1256 xmlElementContentPtr content) {
1257 xmlElementPtr ret;
1258 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001259 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001260 xmlChar *ns, *uqname;
1261
1262 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001263 return(NULL);
1264 }
1265 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001266 return(NULL);
1267 }
1268 switch (type) {
1269 case XML_ELEMENT_TYPE_EMPTY:
1270 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001271 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1272 "xmlAddElementDecl: content != NULL for EMPTY\n",
1273 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001274 return(NULL);
1275 }
1276 break;
1277 case XML_ELEMENT_TYPE_ANY:
1278 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001279 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1280 "xmlAddElementDecl: content != NULL for ANY\n",
1281 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001282 return(NULL);
1283 }
1284 break;
1285 case XML_ELEMENT_TYPE_MIXED:
1286 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001287 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1288 "xmlAddElementDecl: content == NULL for MIXED\n",
1289 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001290 return(NULL);
1291 }
1292 break;
1293 case XML_ELEMENT_TYPE_ELEMENT:
1294 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001295 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1296 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1297 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001298 return(NULL);
1299 }
1300 break;
1301 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001302 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1303 "Internal: ELEMENT decl corrupted invalid type\n",
1304 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001305 return(NULL);
1306 }
1307
1308 /*
1309 * check if name is a QName
1310 */
1311 uqname = xmlSplitQName2(name, &ns);
1312 if (uqname != NULL)
1313 name = uqname;
1314
1315 /*
1316 * Create the Element table if needed.
1317 */
1318 table = (xmlElementTablePtr) dtd->elements;
1319 if (table == NULL) {
1320 table = xmlCreateElementTable();
1321 dtd->elements = (void *) table;
1322 }
1323 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001324 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001325 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001326 if (uqname != NULL)
1327 xmlFree(uqname);
1328 if (ns != NULL)
1329 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001330 return(NULL);
1331 }
1332
Daniel Veillarda10efa82001-04-18 13:09:01 +00001333 /*
1334 * lookup old attributes inserted on an undefined element in the
1335 * internal subset.
1336 */
1337 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1338 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1339 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1340 oldAttributes = ret->attributes;
1341 ret->attributes = NULL;
1342 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1343 xmlFreeElement(ret);
1344 }
Owen Taylor3473f882001-02-23 17:55:21 +00001345 }
Owen Taylor3473f882001-02-23 17:55:21 +00001346
1347 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001348 * The element may already be present if one of its attribute
1349 * was registered first
1350 */
1351 ret = xmlHashLookup2(table, name, ns);
1352 if (ret != NULL) {
1353 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001354#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001355 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001356 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001357 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001358 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1359 "Redefinition of element %s\n",
1360 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001361#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001362 if (uqname != NULL)
1363 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001364 if (ns != NULL)
1365 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001366 return(NULL);
1367 }
1368 } else {
1369 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1370 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001371 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001372 if (uqname != NULL)
1373 xmlFree(uqname);
1374 if (ns != NULL)
1375 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001376 return(NULL);
1377 }
1378 memset(ret, 0, sizeof(xmlElement));
1379 ret->type = XML_ELEMENT_DECL;
1380
1381 /*
1382 * fill the structure.
1383 */
1384 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001385 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001386 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001387 if (uqname != NULL)
1388 xmlFree(uqname);
1389 if (ns != NULL)
1390 xmlFree(ns);
1391 xmlFree(ret);
1392 return(NULL);
1393 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001394 ret->prefix = ns;
1395
1396 /*
1397 * Validity Check:
1398 * Insertion must not fail
1399 */
1400 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001401#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001402 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001403 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001404 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001405 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1406 "Redefinition of element %s\n",
1407 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001408#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001409 xmlFreeElement(ret);
1410 if (uqname != NULL)
1411 xmlFree(uqname);
1412 return(NULL);
1413 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001414 /*
1415 * For new element, may have attributes from earlier
1416 * definition in internal subset
1417 */
1418 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001419 }
1420
1421 /*
1422 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001423 */
1424 ret->etype = type;
Owen Taylor3473f882001-02-23 17:55:21 +00001425 ret->content = xmlCopyElementContent(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001426
1427 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001428 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001429 */
1430 ret->parent = dtd;
1431 ret->doc = dtd->doc;
1432 if (dtd->last == NULL) {
1433 dtd->children = dtd->last = (xmlNodePtr) ret;
1434 } else {
1435 dtd->last->next = (xmlNodePtr) ret;
1436 ret->prev = dtd->last;
1437 dtd->last = (xmlNodePtr) ret;
1438 }
1439 if (uqname != NULL)
1440 xmlFree(uqname);
1441 return(ret);
1442}
1443
1444/**
1445 * xmlFreeElementTable:
1446 * @table: An element table
1447 *
1448 * Deallocate the memory used by an element hash table.
1449 */
1450void
1451xmlFreeElementTable(xmlElementTablePtr table) {
1452 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1453}
1454
Daniel Veillard652327a2003-09-29 18:02:38 +00001455#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001456/**
1457 * xmlCopyElement:
1458 * @elem: An element
1459 *
1460 * Build a copy of an element.
1461 *
1462 * Returns the new xmlElementPtr or NULL in case of error.
1463 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001464static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001465xmlCopyElement(xmlElementPtr elem) {
1466 xmlElementPtr cur;
1467
1468 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1469 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001470 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001471 return(NULL);
1472 }
1473 memset(cur, 0, sizeof(xmlElement));
1474 cur->type = XML_ELEMENT_DECL;
1475 cur->etype = elem->etype;
1476 if (elem->name != NULL)
1477 cur->name = xmlStrdup(elem->name);
1478 else
1479 cur->name = NULL;
1480 if (elem->prefix != NULL)
1481 cur->prefix = xmlStrdup(elem->prefix);
1482 else
1483 cur->prefix = NULL;
1484 cur->content = xmlCopyElementContent(elem->content);
1485 /* TODO : rebuild the attribute list on the copy */
1486 cur->attributes = NULL;
1487 return(cur);
1488}
1489
1490/**
1491 * xmlCopyElementTable:
1492 * @table: An element table
1493 *
1494 * Build a copy of an element table.
1495 *
1496 * Returns the new xmlElementTablePtr or NULL in case of error.
1497 */
1498xmlElementTablePtr
1499xmlCopyElementTable(xmlElementTablePtr table) {
1500 return((xmlElementTablePtr) xmlHashCopy(table,
1501 (xmlHashCopier) xmlCopyElement));
1502}
Daniel Veillard652327a2003-09-29 18:02:38 +00001503#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001504
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001505#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001506/**
1507 * xmlDumpElementDecl:
1508 * @buf: the XML buffer output
1509 * @elem: An element table
1510 *
1511 * This will dump the content of the element declaration as an XML
1512 * DTD definition
1513 */
1514void
1515xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1516 switch (elem->etype) {
1517 case XML_ELEMENT_TYPE_EMPTY:
1518 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001519 if (elem->prefix != NULL) {
1520 xmlBufferWriteCHAR(buf, elem->prefix);
1521 xmlBufferWriteChar(buf, ":");
1522 }
Owen Taylor3473f882001-02-23 17:55:21 +00001523 xmlBufferWriteCHAR(buf, elem->name);
1524 xmlBufferWriteChar(buf, " EMPTY>\n");
1525 break;
1526 case XML_ELEMENT_TYPE_ANY:
1527 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001528 if (elem->prefix != NULL) {
1529 xmlBufferWriteCHAR(buf, elem->prefix);
1530 xmlBufferWriteChar(buf, ":");
1531 }
Owen Taylor3473f882001-02-23 17:55:21 +00001532 xmlBufferWriteCHAR(buf, elem->name);
1533 xmlBufferWriteChar(buf, " ANY>\n");
1534 break;
1535 case XML_ELEMENT_TYPE_MIXED:
1536 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001537 if (elem->prefix != NULL) {
1538 xmlBufferWriteCHAR(buf, elem->prefix);
1539 xmlBufferWriteChar(buf, ":");
1540 }
Owen Taylor3473f882001-02-23 17:55:21 +00001541 xmlBufferWriteCHAR(buf, elem->name);
1542 xmlBufferWriteChar(buf, " ");
1543 xmlDumpElementContent(buf, elem->content, 1);
1544 xmlBufferWriteChar(buf, ">\n");
1545 break;
1546 case XML_ELEMENT_TYPE_ELEMENT:
1547 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001548 if (elem->prefix != NULL) {
1549 xmlBufferWriteCHAR(buf, elem->prefix);
1550 xmlBufferWriteChar(buf, ":");
1551 }
Owen Taylor3473f882001-02-23 17:55:21 +00001552 xmlBufferWriteCHAR(buf, elem->name);
1553 xmlBufferWriteChar(buf, " ");
1554 xmlDumpElementContent(buf, elem->content, 1);
1555 xmlBufferWriteChar(buf, ">\n");
1556 break;
1557 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001558 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1559 "Internal: ELEMENT struct corrupted invalid type\n",
1560 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001561 }
1562}
1563
1564/**
William M. Brack9e660592003-10-20 14:56:06 +00001565 * xmlDumpElementDeclScan:
1566 * @elem: An element table
1567 * @buf: the XML buffer output
1568 *
1569 * This routine is used by the hash scan function. It just reverses
1570 * the arguments.
1571 */
1572static void
1573xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1574 xmlDumpElementDecl(buf, elem);
1575}
1576
1577/**
Owen Taylor3473f882001-02-23 17:55:21 +00001578 * xmlDumpElementTable:
1579 * @buf: the XML buffer output
1580 * @table: An element table
1581 *
1582 * This will dump the content of the element table as an XML DTD definition
1583 */
1584void
1585xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00001586 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001587}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001588#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001589
1590/**
1591 * xmlCreateEnumeration:
1592 * @name: the enumeration name or NULL
1593 *
1594 * create and initialize an enumeration attribute node.
1595 *
1596 * Returns the xmlEnumerationPtr just created or NULL in case
1597 * of error.
1598 */
1599xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001600xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001601 xmlEnumerationPtr ret;
1602
1603 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1604 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001605 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001606 return(NULL);
1607 }
1608 memset(ret, 0, sizeof(xmlEnumeration));
1609
1610 if (name != NULL)
1611 ret->name = xmlStrdup(name);
1612 return(ret);
1613}
1614
1615/**
1616 * xmlFreeEnumeration:
1617 * @cur: the tree to free.
1618 *
1619 * free an enumeration attribute node (recursive).
1620 */
1621void
1622xmlFreeEnumeration(xmlEnumerationPtr cur) {
1623 if (cur == NULL) return;
1624
1625 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1626
1627 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001628 xmlFree(cur);
1629}
1630
Daniel Veillard652327a2003-09-29 18:02:38 +00001631#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001632/**
1633 * xmlCopyEnumeration:
1634 * @cur: the tree to copy.
1635 *
1636 * Copy an enumeration attribute node (recursive).
1637 *
1638 * Returns the xmlEnumerationPtr just created or NULL in case
1639 * of error.
1640 */
1641xmlEnumerationPtr
1642xmlCopyEnumeration(xmlEnumerationPtr cur) {
1643 xmlEnumerationPtr ret;
1644
1645 if (cur == NULL) return(NULL);
1646 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1647
1648 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1649 else ret->next = NULL;
1650
1651 return(ret);
1652}
Daniel Veillard652327a2003-09-29 18:02:38 +00001653#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001654
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001655#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001656/**
1657 * xmlDumpEnumeration:
1658 * @buf: the XML buffer output
1659 * @enum: An enumeration
1660 *
1661 * This will dump the content of the enumeration
1662 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001663static void
Owen Taylor3473f882001-02-23 17:55:21 +00001664xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1665 if (cur == NULL) return;
1666
1667 xmlBufferWriteCHAR(buf, cur->name);
1668 if (cur->next == NULL)
1669 xmlBufferWriteChar(buf, ")");
1670 else {
1671 xmlBufferWriteChar(buf, " | ");
1672 xmlDumpEnumeration(buf, cur->next);
1673 }
1674}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001675#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001676
1677/**
1678 * xmlCreateAttributeTable:
1679 *
1680 * create and initialize an empty attribute hash table.
1681 *
1682 * Returns the xmlAttributeTablePtr just created or NULL in case
1683 * of error.
1684 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001685static xmlAttributeTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001686xmlCreateAttributeTable(void) {
1687 return(xmlHashCreate(0));
1688}
1689
Daniel Veillard4432df22003-09-28 18:58:27 +00001690#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001691/**
1692 * xmlScanAttributeDeclCallback:
1693 * @attr: the attribute decl
1694 * @list: the list to update
1695 *
1696 * Callback called by xmlScanAttributeDecl when a new attribute
1697 * has to be entered in the list.
1698 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001699static void
Owen Taylor3473f882001-02-23 17:55:21 +00001700xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001701 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001702 attr->nexth = *list;
1703 *list = attr;
1704}
1705
1706/**
1707 * xmlScanAttributeDecl:
1708 * @dtd: pointer to the DTD
1709 * @elem: the element name
1710 *
1711 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001712 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001713 *
1714 * Returns the pointer to the first attribute decl in the chain,
1715 * possibly NULL.
1716 */
1717xmlAttributePtr
1718xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1719 xmlAttributePtr ret = NULL;
1720 xmlAttributeTablePtr table;
1721
1722 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001723 return(NULL);
1724 }
1725 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001726 return(NULL);
1727 }
1728 table = (xmlAttributeTablePtr) dtd->attributes;
1729 if (table == NULL)
1730 return(NULL);
1731
1732 /* WRONG !!! */
1733 xmlHashScan3(table, NULL, NULL, elem,
1734 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1735 return(ret);
1736}
1737
1738/**
1739 * xmlScanIDAttributeDecl:
1740 * @ctxt: the validation context
1741 * @elem: the element name
1742 *
1743 * Verify that the element don't have too many ID attributes
1744 * declared.
1745 *
1746 * Returns the number of ID attributes found.
1747 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001748static int
Owen Taylor3473f882001-02-23 17:55:21 +00001749xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1750 xmlAttributePtr cur;
1751 int ret = 0;
1752
1753 if (elem == NULL) return(0);
1754 cur = elem->attributes;
1755 while (cur != NULL) {
1756 if (cur->atype == XML_ATTRIBUTE_ID) {
1757 ret ++;
1758 if (ret > 1)
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001759 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001760 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001761 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001762 }
1763 cur = cur->nexth;
1764 }
1765 return(ret);
1766}
Daniel Veillard4432df22003-09-28 18:58:27 +00001767#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001768
1769/**
1770 * xmlFreeAttribute:
1771 * @elem: An attribute
1772 *
1773 * Deallocate the memory used by an attribute definition
1774 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001775static void
Owen Taylor3473f882001-02-23 17:55:21 +00001776xmlFreeAttribute(xmlAttributePtr attr) {
1777 if (attr == NULL) return;
1778 xmlUnlinkNode((xmlNodePtr) attr);
1779 if (attr->tree != NULL)
1780 xmlFreeEnumeration(attr->tree);
1781 if (attr->elem != NULL)
1782 xmlFree((xmlChar *) attr->elem);
1783 if (attr->name != NULL)
1784 xmlFree((xmlChar *) attr->name);
1785 if (attr->defaultValue != NULL)
1786 xmlFree((xmlChar *) attr->defaultValue);
1787 if (attr->prefix != NULL)
1788 xmlFree((xmlChar *) attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001789 xmlFree(attr);
1790}
1791
1792
1793/**
1794 * xmlAddAttributeDecl:
1795 * @ctxt: the validation context
1796 * @dtd: pointer to the DTD
1797 * @elem: the element name
1798 * @name: the attribute name
1799 * @ns: the attribute namespace prefix
1800 * @type: the attribute type
1801 * @def: the attribute default type
1802 * @defaultValue: the attribute default value
1803 * @tree: if it's an enumeration, the associated list
1804 *
1805 * Register a new attribute declaration
1806 * Note that @tree becomes the ownership of the DTD
1807 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001808 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001809 */
1810xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001811xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001812 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001813 const xmlChar *name, const xmlChar *ns,
1814 xmlAttributeType type, xmlAttributeDefault def,
1815 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1816 xmlAttributePtr ret;
1817 xmlAttributeTablePtr table;
1818 xmlElementPtr elemDef;
1819
1820 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001821 xmlFreeEnumeration(tree);
1822 return(NULL);
1823 }
1824 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001825 xmlFreeEnumeration(tree);
1826 return(NULL);
1827 }
1828 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001829 xmlFreeEnumeration(tree);
1830 return(NULL);
1831 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001832
Daniel Veillard4432df22003-09-28 18:58:27 +00001833#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001834 /*
1835 * Check the type and possibly the default value.
1836 */
1837 switch (type) {
1838 case XML_ATTRIBUTE_CDATA:
1839 break;
1840 case XML_ATTRIBUTE_ID:
1841 break;
1842 case XML_ATTRIBUTE_IDREF:
1843 break;
1844 case XML_ATTRIBUTE_IDREFS:
1845 break;
1846 case XML_ATTRIBUTE_ENTITY:
1847 break;
1848 case XML_ATTRIBUTE_ENTITIES:
1849 break;
1850 case XML_ATTRIBUTE_NMTOKEN:
1851 break;
1852 case XML_ATTRIBUTE_NMTOKENS:
1853 break;
1854 case XML_ATTRIBUTE_ENUMERATION:
1855 break;
1856 case XML_ATTRIBUTE_NOTATION:
1857 break;
1858 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001859 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1860 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1861 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001862 xmlFreeEnumeration(tree);
1863 return(NULL);
1864 }
1865 if ((defaultValue != NULL) &&
1866 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001867 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1868 "Attribute %s of %s: invalid default value\n",
1869 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00001870 defaultValue = NULL;
Daniel Veillardd01fd3e2002-02-18 22:27:47 +00001871 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001872 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001873#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001874
1875 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001876 * Check first that an attribute defined in the external subset wasn't
1877 * already defined in the internal subset
1878 */
1879 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1880 (dtd->doc->intSubset != NULL) &&
1881 (dtd->doc->intSubset->attributes != NULL)) {
1882 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1883 if (ret != NULL)
1884 return(NULL);
1885 }
1886
1887 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001888 * Create the Attribute table if needed.
1889 */
1890 table = (xmlAttributeTablePtr) dtd->attributes;
1891 if (table == NULL) {
1892 table = xmlCreateAttributeTable();
1893 dtd->attributes = (void *) table;
1894 }
1895 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001896 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001897 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001898 return(NULL);
1899 }
1900
1901
1902 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1903 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001904 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001905 return(NULL);
1906 }
1907 memset(ret, 0, sizeof(xmlAttribute));
1908 ret->type = XML_ATTRIBUTE_DECL;
1909
1910 /*
1911 * fill the structure.
1912 */
1913 ret->atype = type;
1914 ret->name = xmlStrdup(name);
1915 ret->prefix = xmlStrdup(ns);
1916 ret->elem = xmlStrdup(elem);
1917 ret->def = def;
1918 ret->tree = tree;
1919 if (defaultValue != NULL)
1920 ret->defaultValue = xmlStrdup(defaultValue);
1921
1922 /*
1923 * Validity Check:
1924 * Search the DTD for previous declarations of the ATTLIST
1925 */
1926 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001927#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001928 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001929 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00001930 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001931 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00001932 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001933 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001934#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001935 xmlFreeAttribute(ret);
1936 return(NULL);
1937 }
1938
1939 /*
1940 * Validity Check:
1941 * Multiple ID per element
1942 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001943 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001944 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00001945
Daniel Veillard4432df22003-09-28 18:58:27 +00001946#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001947 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00001948 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001949 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00001950 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001951 elem, name, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00001952 ctxt->valid = 0;
1953 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001954#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00001955
Daniel Veillard48da9102001-08-07 01:10:10 +00001956 /*
1957 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001958 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00001959 */
1960 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1961 ((ret->prefix != NULL &&
1962 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1963 ret->nexth = elemDef->attributes;
1964 elemDef->attributes = ret;
1965 } else {
1966 xmlAttributePtr tmp = elemDef->attributes;
1967
1968 while ((tmp != NULL) &&
1969 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1970 ((ret->prefix != NULL &&
1971 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1972 if (tmp->nexth == NULL)
1973 break;
1974 tmp = tmp->nexth;
1975 }
1976 if (tmp != NULL) {
1977 ret->nexth = tmp->nexth;
1978 tmp->nexth = ret;
1979 } else {
1980 ret->nexth = elemDef->attributes;
1981 elemDef->attributes = ret;
1982 }
1983 }
Owen Taylor3473f882001-02-23 17:55:21 +00001984 }
1985
1986 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001987 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001988 */
1989 ret->parent = dtd;
1990 ret->doc = dtd->doc;
1991 if (dtd->last == NULL) {
1992 dtd->children = dtd->last = (xmlNodePtr) ret;
1993 } else {
1994 dtd->last->next = (xmlNodePtr) ret;
1995 ret->prev = dtd->last;
1996 dtd->last = (xmlNodePtr) ret;
1997 }
1998 return(ret);
1999}
2000
2001/**
2002 * xmlFreeAttributeTable:
2003 * @table: An attribute table
2004 *
2005 * Deallocate the memory used by an entities hash table.
2006 */
2007void
2008xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2009 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
2010}
2011
Daniel Veillard652327a2003-09-29 18:02:38 +00002012#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002013/**
2014 * xmlCopyAttribute:
2015 * @attr: An attribute
2016 *
2017 * Build a copy of an attribute.
2018 *
2019 * Returns the new xmlAttributePtr or NULL in case of error.
2020 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002021static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002022xmlCopyAttribute(xmlAttributePtr attr) {
2023 xmlAttributePtr cur;
2024
2025 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2026 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002027 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002028 return(NULL);
2029 }
2030 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00002031 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00002032 cur->atype = attr->atype;
2033 cur->def = attr->def;
2034 cur->tree = xmlCopyEnumeration(attr->tree);
2035 if (attr->elem != NULL)
2036 cur->elem = xmlStrdup(attr->elem);
2037 if (attr->name != NULL)
2038 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002039 if (attr->prefix != NULL)
2040 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002041 if (attr->defaultValue != NULL)
2042 cur->defaultValue = xmlStrdup(attr->defaultValue);
2043 return(cur);
2044}
2045
2046/**
2047 * xmlCopyAttributeTable:
2048 * @table: An attribute table
2049 *
2050 * Build a copy of an attribute table.
2051 *
2052 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2053 */
2054xmlAttributeTablePtr
2055xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2056 return((xmlAttributeTablePtr) xmlHashCopy(table,
2057 (xmlHashCopier) xmlCopyAttribute));
2058}
Daniel Veillard652327a2003-09-29 18:02:38 +00002059#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002060
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002061#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002062/**
2063 * xmlDumpAttributeDecl:
2064 * @buf: the XML buffer output
2065 * @attr: An attribute declaration
2066 *
2067 * This will dump the content of the attribute declaration as an XML
2068 * DTD definition
2069 */
2070void
2071xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2072 xmlBufferWriteChar(buf, "<!ATTLIST ");
2073 xmlBufferWriteCHAR(buf, attr->elem);
2074 xmlBufferWriteChar(buf, " ");
2075 if (attr->prefix != NULL) {
2076 xmlBufferWriteCHAR(buf, attr->prefix);
2077 xmlBufferWriteChar(buf, ":");
2078 }
2079 xmlBufferWriteCHAR(buf, attr->name);
2080 switch (attr->atype) {
2081 case XML_ATTRIBUTE_CDATA:
2082 xmlBufferWriteChar(buf, " CDATA");
2083 break;
2084 case XML_ATTRIBUTE_ID:
2085 xmlBufferWriteChar(buf, " ID");
2086 break;
2087 case XML_ATTRIBUTE_IDREF:
2088 xmlBufferWriteChar(buf, " IDREF");
2089 break;
2090 case XML_ATTRIBUTE_IDREFS:
2091 xmlBufferWriteChar(buf, " IDREFS");
2092 break;
2093 case XML_ATTRIBUTE_ENTITY:
2094 xmlBufferWriteChar(buf, " ENTITY");
2095 break;
2096 case XML_ATTRIBUTE_ENTITIES:
2097 xmlBufferWriteChar(buf, " ENTITIES");
2098 break;
2099 case XML_ATTRIBUTE_NMTOKEN:
2100 xmlBufferWriteChar(buf, " NMTOKEN");
2101 break;
2102 case XML_ATTRIBUTE_NMTOKENS:
2103 xmlBufferWriteChar(buf, " NMTOKENS");
2104 break;
2105 case XML_ATTRIBUTE_ENUMERATION:
2106 xmlBufferWriteChar(buf, " (");
2107 xmlDumpEnumeration(buf, attr->tree);
2108 break;
2109 case XML_ATTRIBUTE_NOTATION:
2110 xmlBufferWriteChar(buf, " NOTATION (");
2111 xmlDumpEnumeration(buf, attr->tree);
2112 break;
2113 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002114 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2115 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2116 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002117 }
2118 switch (attr->def) {
2119 case XML_ATTRIBUTE_NONE:
2120 break;
2121 case XML_ATTRIBUTE_REQUIRED:
2122 xmlBufferWriteChar(buf, " #REQUIRED");
2123 break;
2124 case XML_ATTRIBUTE_IMPLIED:
2125 xmlBufferWriteChar(buf, " #IMPLIED");
2126 break;
2127 case XML_ATTRIBUTE_FIXED:
2128 xmlBufferWriteChar(buf, " #FIXED");
2129 break;
2130 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002131 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2132 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2133 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002134 }
2135 if (attr->defaultValue != NULL) {
2136 xmlBufferWriteChar(buf, " ");
2137 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2138 }
2139 xmlBufferWriteChar(buf, ">\n");
2140}
2141
2142/**
William M. Brack9e660592003-10-20 14:56:06 +00002143 * xmlDumpAttributeDeclScan:
2144 * @attr: An attribute declaration
2145 * @buf: the XML buffer output
2146 *
2147 * This is used with the hash scan function - just reverses arguments
2148 */
2149static void
2150xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2151 xmlDumpAttributeDecl(buf, attr);
2152}
2153
2154/**
Owen Taylor3473f882001-02-23 17:55:21 +00002155 * xmlDumpAttributeTable:
2156 * @buf: the XML buffer output
2157 * @table: An attribute table
2158 *
2159 * This will dump the content of the attribute table as an XML DTD definition
2160 */
2161void
2162xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002163 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002164}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002165#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002166
2167/************************************************************************
2168 * *
2169 * NOTATIONs *
2170 * *
2171 ************************************************************************/
2172/**
2173 * xmlCreateNotationTable:
2174 *
2175 * create and initialize an empty notation hash table.
2176 *
2177 * Returns the xmlNotationTablePtr just created or NULL in case
2178 * of error.
2179 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002180static xmlNotationTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002181xmlCreateNotationTable(void) {
2182 return(xmlHashCreate(0));
2183}
2184
2185/**
2186 * xmlFreeNotation:
2187 * @not: A notation
2188 *
2189 * Deallocate the memory used by an notation definition
2190 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002191static void
Owen Taylor3473f882001-02-23 17:55:21 +00002192xmlFreeNotation(xmlNotationPtr nota) {
2193 if (nota == NULL) return;
2194 if (nota->name != NULL)
2195 xmlFree((xmlChar *) nota->name);
2196 if (nota->PublicID != NULL)
2197 xmlFree((xmlChar *) nota->PublicID);
2198 if (nota->SystemID != NULL)
2199 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002200 xmlFree(nota);
2201}
2202
2203
2204/**
2205 * xmlAddNotationDecl:
2206 * @dtd: pointer to the DTD
2207 * @ctxt: the validation context
2208 * @name: the entity name
2209 * @PublicID: the public identifier or NULL
2210 * @SystemID: the system identifier or NULL
2211 *
2212 * Register a new notation declaration
2213 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002214 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002215 */
2216xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002217xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002218 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002219 const xmlChar *PublicID, const xmlChar *SystemID) {
2220 xmlNotationPtr ret;
2221 xmlNotationTablePtr table;
2222
2223 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002224 return(NULL);
2225 }
2226 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002227 return(NULL);
2228 }
2229 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002230 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002231 }
2232
2233 /*
2234 * Create the Notation table if needed.
2235 */
2236 table = (xmlNotationTablePtr) dtd->notations;
2237 if (table == NULL)
2238 dtd->notations = table = xmlCreateNotationTable();
2239 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002240 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002241 "xmlAddNotationDecl: Table creation failed!\n");
2242 return(NULL);
2243 }
2244
2245 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2246 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002247 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002248 return(NULL);
2249 }
2250 memset(ret, 0, sizeof(xmlNotation));
2251
2252 /*
2253 * fill the structure.
2254 */
2255 ret->name = xmlStrdup(name);
2256 if (SystemID != NULL)
2257 ret->SystemID = xmlStrdup(SystemID);
2258 if (PublicID != NULL)
2259 ret->PublicID = xmlStrdup(PublicID);
2260
2261 /*
2262 * Validity Check:
2263 * Check the DTD for previous declarations of the ATTLIST
2264 */
2265 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002266#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002267 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2268 "xmlAddNotationDecl: %s already defined\n",
2269 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002270#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002271 xmlFreeNotation(ret);
2272 return(NULL);
2273 }
2274 return(ret);
2275}
2276
2277/**
2278 * xmlFreeNotationTable:
2279 * @table: An notation table
2280 *
2281 * Deallocate the memory used by an entities hash table.
2282 */
2283void
2284xmlFreeNotationTable(xmlNotationTablePtr table) {
2285 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2286}
2287
Daniel Veillard652327a2003-09-29 18:02:38 +00002288#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002289/**
2290 * xmlCopyNotation:
2291 * @nota: A notation
2292 *
2293 * Build a copy of a notation.
2294 *
2295 * Returns the new xmlNotationPtr or NULL in case of error.
2296 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002297static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002298xmlCopyNotation(xmlNotationPtr nota) {
2299 xmlNotationPtr cur;
2300
2301 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2302 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002303 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002304 return(NULL);
2305 }
2306 if (nota->name != NULL)
2307 cur->name = xmlStrdup(nota->name);
2308 else
2309 cur->name = NULL;
2310 if (nota->PublicID != NULL)
2311 cur->PublicID = xmlStrdup(nota->PublicID);
2312 else
2313 cur->PublicID = NULL;
2314 if (nota->SystemID != NULL)
2315 cur->SystemID = xmlStrdup(nota->SystemID);
2316 else
2317 cur->SystemID = NULL;
2318 return(cur);
2319}
2320
2321/**
2322 * xmlCopyNotationTable:
2323 * @table: A notation table
2324 *
2325 * Build a copy of a notation table.
2326 *
2327 * Returns the new xmlNotationTablePtr or NULL in case of error.
2328 */
2329xmlNotationTablePtr
2330xmlCopyNotationTable(xmlNotationTablePtr table) {
2331 return((xmlNotationTablePtr) xmlHashCopy(table,
2332 (xmlHashCopier) xmlCopyNotation));
2333}
Daniel Veillard652327a2003-09-29 18:02:38 +00002334#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002335
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002336#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002337/**
2338 * xmlDumpNotationDecl:
2339 * @buf: the XML buffer output
2340 * @nota: A notation declaration
2341 *
2342 * This will dump the content the notation declaration as an XML DTD definition
2343 */
2344void
2345xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2346 xmlBufferWriteChar(buf, "<!NOTATION ");
2347 xmlBufferWriteCHAR(buf, nota->name);
2348 if (nota->PublicID != NULL) {
2349 xmlBufferWriteChar(buf, " PUBLIC ");
2350 xmlBufferWriteQuotedString(buf, nota->PublicID);
2351 if (nota->SystemID != NULL) {
2352 xmlBufferWriteChar(buf, " ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002353 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002354 }
2355 } else {
2356 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002357 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002358 }
2359 xmlBufferWriteChar(buf, " >\n");
2360}
2361
2362/**
William M. Brack9e660592003-10-20 14:56:06 +00002363 * xmlDumpNotationDeclScan:
2364 * @nota: A notation declaration
2365 * @buf: the XML buffer output
2366 *
2367 * This is called with the hash scan function, and just reverses args
2368 */
2369static void
2370xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2371 xmlDumpNotationDecl(buf, nota);
2372}
2373
2374/**
Owen Taylor3473f882001-02-23 17:55:21 +00002375 * xmlDumpNotationTable:
2376 * @buf: the XML buffer output
2377 * @table: A notation table
2378 *
2379 * This will dump the content of the notation table as an XML DTD definition
2380 */
2381void
2382xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002383 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002384}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002385#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002386
2387/************************************************************************
2388 * *
2389 * IDs *
2390 * *
2391 ************************************************************************/
2392/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002393 * DICT_FREE:
2394 * @str: a string
2395 *
2396 * Free a string if it is not owned by the "dict" dictionnary in the
2397 * current scope
2398 */
2399#define DICT_FREE(str) \
2400 if ((str) && ((!dict) || \
2401 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2402 xmlFree((char *)(str));
2403
2404/**
Owen Taylor3473f882001-02-23 17:55:21 +00002405 * xmlCreateIDTable:
2406 *
2407 * create and initialize an empty id hash table.
2408 *
2409 * Returns the xmlIDTablePtr just created or NULL in case
2410 * of error.
2411 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002412static xmlIDTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002413xmlCreateIDTable(void) {
2414 return(xmlHashCreate(0));
2415}
2416
2417/**
2418 * xmlFreeID:
2419 * @not: A id
2420 *
2421 * Deallocate the memory used by an id definition
2422 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002423static void
Owen Taylor3473f882001-02-23 17:55:21 +00002424xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002425 xmlDictPtr dict = NULL;
2426
Owen Taylor3473f882001-02-23 17:55:21 +00002427 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002428
2429 if (id->doc != NULL)
2430 dict = id->doc->dict;
2431
Owen Taylor3473f882001-02-23 17:55:21 +00002432 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002433 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002434 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002435 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002436 xmlFree(id);
2437}
2438
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002439
Owen Taylor3473f882001-02-23 17:55:21 +00002440/**
2441 * xmlAddID:
2442 * @ctxt: the validation context
2443 * @doc: pointer to the document
2444 * @value: the value name
2445 * @attr: the attribute holding the ID
2446 *
2447 * Register a new id declaration
2448 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002449 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002450 */
2451xmlIDPtr
2452xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2453 xmlAttrPtr attr) {
2454 xmlIDPtr ret;
2455 xmlIDTablePtr table;
2456
2457 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002458 return(NULL);
2459 }
2460 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002461 return(NULL);
2462 }
2463 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002464 return(NULL);
2465 }
2466
2467 /*
2468 * Create the ID table if needed.
2469 */
2470 table = (xmlIDTablePtr) doc->ids;
2471 if (table == NULL)
2472 doc->ids = table = xmlCreateIDTable();
2473 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002474 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002475 "xmlAddID: Table creation failed!\n");
2476 return(NULL);
2477 }
2478
2479 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2480 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002481 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002482 return(NULL);
2483 }
2484
2485 /*
2486 * fill the structure.
2487 */
2488 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002489 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002490 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2491 /*
2492 * Operating in streaming mode, attr is gonna disapear
2493 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002494 if (doc->dict != NULL)
2495 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2496 else
2497 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002498 ret->attr = NULL;
2499 } else {
2500 ret->attr = attr;
2501 ret->name = NULL;
2502 }
2503 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002504
2505 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002506#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002507 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002508 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002509 */
Daniel Veillardd3669b22004-02-25 12:34:55 +00002510 if ((ctxt != NULL) && (ctxt->error != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002511 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2512 "ID %s already defined\n",
2513 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002514 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002515#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002516 xmlFreeID(ret);
2517 return(NULL);
2518 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002519 if (attr != NULL)
2520 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002521 return(ret);
2522}
2523
2524/**
2525 * xmlFreeIDTable:
2526 * @table: An id table
2527 *
2528 * Deallocate the memory used by an ID hash table.
2529 */
2530void
2531xmlFreeIDTable(xmlIDTablePtr table) {
2532 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2533}
2534
2535/**
2536 * xmlIsID:
2537 * @doc: the document
2538 * @elem: the element carrying the attribute
2539 * @attr: the attribute
2540 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002541 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002542 * then this is done if DTD loading has been requested. In the case
2543 * of HTML documents parsed with the HTML parser, then ID detection is
2544 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002545 *
2546 * Returns 0 or 1 depending on the lookup result
2547 */
2548int
2549xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2550 if (doc == NULL) return(0);
2551 if (attr == NULL) return(0);
2552 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2553 return(0);
2554 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard9ba8e382003-10-28 21:31:45 +00002555 if (((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2556 (xmlStrEqual(BAD_CAST "name", attr->name))) &&
2557 ((elem != NULL) && (!xmlStrEqual(elem->name, BAD_CAST "input"))))
Owen Taylor3473f882001-02-23 17:55:21 +00002558 return(1);
2559 return(0);
2560 } else {
2561 xmlAttributePtr attrDecl;
2562
2563 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002564 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002565 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002566 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002567
2568 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002569 if (fullname == NULL)
2570 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002571 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2572 attr->name);
2573 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2574 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2575 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002576 if ((fullname != fn) && (fullname != elem->name))
2577 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002578 } else {
2579 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2580 attr->name);
2581 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2582 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2583 attr->name);
2584 }
Owen Taylor3473f882001-02-23 17:55:21 +00002585
2586 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2587 return(1);
2588 }
2589 return(0);
2590}
2591
2592/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002593 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002594 * @doc: the document
2595 * @attr: the attribute
2596 *
2597 * Remove the given attribute from the ID table maintained internally.
2598 *
2599 * Returns -1 if the lookup failed and 0 otherwise
2600 */
2601int
2602xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002603 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002604 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002605 xmlChar *ID;
2606
2607 if (doc == NULL) return(-1);
2608 if (attr == NULL) return(-1);
2609 table = (xmlIDTablePtr) doc->ids;
2610 if (table == NULL)
2611 return(-1);
2612
2613 if (attr == NULL)
2614 return(-1);
2615 ID = xmlNodeListGetString(doc, attr->children, 1);
2616 if (ID == NULL)
2617 return(-1);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002618 id = xmlHashLookup(table, ID);
2619 if (id == NULL || id->attr != attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002620 xmlFree(ID);
2621 return(-1);
2622 }
2623 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
2624 xmlFree(ID);
2625 return(0);
2626}
2627
2628/**
2629 * xmlGetID:
2630 * @doc: pointer to the document
2631 * @ID: the ID value
2632 *
2633 * Search the attribute declaring the given ID
2634 *
2635 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2636 */
2637xmlAttrPtr
2638xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2639 xmlIDTablePtr table;
2640 xmlIDPtr id;
2641
2642 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002643 return(NULL);
2644 }
2645
2646 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002647 return(NULL);
2648 }
2649
2650 table = (xmlIDTablePtr) doc->ids;
2651 if (table == NULL)
2652 return(NULL);
2653
2654 id = xmlHashLookup(table, ID);
2655 if (id == NULL)
2656 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002657 if (id->attr == NULL) {
2658 /*
2659 * We are operating on a stream, return a well known reference
2660 * since the attribute node doesn't exist anymore
2661 */
2662 return((xmlAttrPtr) doc);
2663 }
Owen Taylor3473f882001-02-23 17:55:21 +00002664 return(id->attr);
2665}
2666
2667/************************************************************************
2668 * *
2669 * Refs *
2670 * *
2671 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002672typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002673{
2674 xmlListPtr l;
2675 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002676} xmlRemoveMemo;
2677
2678typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2679
2680typedef struct xmlValidateMemo_t
2681{
2682 xmlValidCtxtPtr ctxt;
2683 const xmlChar *name;
2684} xmlValidateMemo;
2685
2686typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002687
2688/**
2689 * xmlCreateRefTable:
2690 *
2691 * create and initialize an empty ref hash table.
2692 *
2693 * Returns the xmlRefTablePtr just created or NULL in case
2694 * of error.
2695 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002696static xmlRefTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002697xmlCreateRefTable(void) {
2698 return(xmlHashCreate(0));
2699}
2700
2701/**
2702 * xmlFreeRef:
2703 * @lk: A list link
2704 *
2705 * Deallocate the memory used by a ref definition
2706 */
2707static void
2708xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002709 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2710 if (ref == NULL) return;
2711 if (ref->value != NULL)
2712 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002713 if (ref->name != NULL)
2714 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002715 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002716}
2717
2718/**
2719 * xmlFreeRefList:
2720 * @list_ref: A list of references.
2721 *
2722 * Deallocate the memory used by a list of references
2723 */
2724static void
2725xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002726 if (list_ref == NULL) return;
2727 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002728}
2729
2730/**
2731 * xmlWalkRemoveRef:
2732 * @data: Contents of current link
2733 * @user: Value supplied by the user
2734 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002735 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002736 */
2737static int
2738xmlWalkRemoveRef(const void *data, const void *user)
2739{
Daniel Veillard37721922001-05-04 15:21:12 +00002740 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2741 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2742 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002743
Daniel Veillard37721922001-05-04 15:21:12 +00002744 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2745 xmlListRemoveFirst(ref_list, (void *)data);
2746 return 0;
2747 }
2748 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002749}
2750
2751/**
Daniel Veillard770075b2004-02-25 10:44:30 +00002752 * xmlDummyCompare
2753 * @data0: Value supplied by the user
2754 * @data1: Value supplied by the user
2755 *
2756 * Do nothing, return 0. Used to create unordered lists.
2757 */
2758static int
Daniel Veillardf54cd532004-02-25 11:52:31 +00002759xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2760 const void *data1 ATTRIBUTE_UNUSED)
Daniel Veillard770075b2004-02-25 10:44:30 +00002761{
2762 return (0);
2763}
2764
2765/**
Owen Taylor3473f882001-02-23 17:55:21 +00002766 * xmlAddRef:
2767 * @ctxt: the validation context
2768 * @doc: pointer to the document
2769 * @value: the value name
2770 * @attr: the attribute holding the Ref
2771 *
2772 * Register a new ref declaration
2773 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002774 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002775 */
2776xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002777xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002778 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002779 xmlRefPtr ret;
2780 xmlRefTablePtr table;
2781 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002782
Daniel Veillard37721922001-05-04 15:21:12 +00002783 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002784 return(NULL);
2785 }
2786 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002787 return(NULL);
2788 }
2789 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002790 return(NULL);
2791 }
Owen Taylor3473f882001-02-23 17:55:21 +00002792
Daniel Veillard37721922001-05-04 15:21:12 +00002793 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002794 * Create the Ref table if needed.
2795 */
Daniel Veillard37721922001-05-04 15:21:12 +00002796 table = (xmlRefTablePtr) doc->refs;
2797 if (table == NULL)
2798 doc->refs = table = xmlCreateRefTable();
2799 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002800 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002801 "xmlAddRef: Table creation failed!\n");
2802 return(NULL);
2803 }
Owen Taylor3473f882001-02-23 17:55:21 +00002804
Daniel Veillard37721922001-05-04 15:21:12 +00002805 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2806 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002807 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002808 return(NULL);
2809 }
Owen Taylor3473f882001-02-23 17:55:21 +00002810
Daniel Veillard37721922001-05-04 15:21:12 +00002811 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002812 * fill the structure.
2813 */
Daniel Veillard37721922001-05-04 15:21:12 +00002814 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002815 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2816 /*
2817 * Operating in streaming mode, attr is gonna disapear
2818 */
2819 ret->name = xmlStrdup(attr->name);
2820 ret->attr = NULL;
2821 } else {
2822 ret->name = NULL;
2823 ret->attr = attr;
2824 }
2825 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002826
Daniel Veillard37721922001-05-04 15:21:12 +00002827 /* To add a reference :-
2828 * References are maintained as a list of references,
2829 * Lookup the entry, if no entry create new nodelist
2830 * Add the owning node to the NodeList
2831 * Return the ref
2832 */
Owen Taylor3473f882001-02-23 17:55:21 +00002833
Daniel Veillard37721922001-05-04 15:21:12 +00002834 if (NULL == (ref_list = xmlHashLookup(table, value))) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002835 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002836 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2837 "xmlAddRef: Reference list creation failed!\n",
2838 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002839 return(NULL);
2840 }
2841 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2842 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002843 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2844 "xmlAddRef: Reference list insertion failed!\n",
2845 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002846 return(NULL);
2847 }
2848 }
Daniel Veillard965983a2004-02-17 16:30:24 +00002849/* xmlListInsert(ref_list, ret); */
2850 xmlListAppend(ref_list, ret);
Daniel Veillard37721922001-05-04 15:21:12 +00002851 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002852}
2853
2854/**
2855 * xmlFreeRefTable:
2856 * @table: An ref table
2857 *
2858 * Deallocate the memory used by an Ref hash table.
2859 */
2860void
2861xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002862 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002863}
2864
2865/**
2866 * xmlIsRef:
2867 * @doc: the document
2868 * @elem: the element carrying the attribute
2869 * @attr: the attribute
2870 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002871 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00002872 * then this is simple, otherwise we use an heuristic: name Ref (upper
2873 * or lowercase).
2874 *
2875 * Returns 0 or 1 depending on the lookup result
2876 */
2877int
2878xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002879 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2880 return(0);
2881 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2882 /* TODO @@@ */
2883 return(0);
2884 } else {
2885 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00002886
Daniel Veillard37721922001-05-04 15:21:12 +00002887 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2888 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2889 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2890 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002891
Daniel Veillard37721922001-05-04 15:21:12 +00002892 if ((attrDecl != NULL) &&
2893 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2894 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2895 return(1);
2896 }
2897 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002898}
2899
2900/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002901 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00002902 * @doc: the document
2903 * @attr: the attribute
2904 *
2905 * Remove the given attribute from the Ref table maintained internally.
2906 *
2907 * Returns -1 if the lookup failed and 0 otherwise
2908 */
2909int
2910xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002911 xmlListPtr ref_list;
2912 xmlRefTablePtr table;
2913 xmlChar *ID;
2914 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00002915
Daniel Veillard37721922001-05-04 15:21:12 +00002916 if (doc == NULL) return(-1);
2917 if (attr == NULL) return(-1);
2918 table = (xmlRefTablePtr) doc->refs;
2919 if (table == NULL)
2920 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002921
Daniel Veillard37721922001-05-04 15:21:12 +00002922 if (attr == NULL)
2923 return(-1);
2924 ID = xmlNodeListGetString(doc, attr->children, 1);
2925 if (ID == NULL)
2926 return(-1);
2927 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00002928
Daniel Veillard37721922001-05-04 15:21:12 +00002929 if(ref_list == NULL) {
2930 xmlFree(ID);
2931 return (-1);
2932 }
2933 /* At this point, ref_list refers to a list of references which
2934 * have the same key as the supplied attr. Our list of references
2935 * is ordered by reference address and we don't have that information
2936 * here to use when removing. We'll have to walk the list and
2937 * check for a matching attribute, when we find one stop the walk
2938 * and remove the entry.
2939 * The list is ordered by reference, so that means we don't have the
2940 * key. Passing the list and the reference to the walker means we
2941 * will have enough data to be able to remove the entry.
2942 */
2943 target.l = ref_list;
2944 target.ap = attr;
2945
2946 /* Remove the supplied attr from our list */
2947 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00002948
Daniel Veillard37721922001-05-04 15:21:12 +00002949 /*If the list is empty then remove the list entry in the hash */
2950 if (xmlListEmpty(ref_list))
2951 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2952 xmlFreeRefList);
2953 xmlFree(ID);
2954 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002955}
2956
2957/**
2958 * xmlGetRefs:
2959 * @doc: pointer to the document
2960 * @ID: the ID value
2961 *
2962 * Find the set of references for the supplied ID.
2963 *
2964 * Returns NULL if not found, otherwise node set for the ID.
2965 */
2966xmlListPtr
2967xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00002968 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00002969
Daniel Veillard37721922001-05-04 15:21:12 +00002970 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002971 return(NULL);
2972 }
Owen Taylor3473f882001-02-23 17:55:21 +00002973
Daniel Veillard37721922001-05-04 15:21:12 +00002974 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002975 return(NULL);
2976 }
Owen Taylor3473f882001-02-23 17:55:21 +00002977
Daniel Veillard37721922001-05-04 15:21:12 +00002978 table = (xmlRefTablePtr) doc->refs;
2979 if (table == NULL)
2980 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002981
Daniel Veillard37721922001-05-04 15:21:12 +00002982 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00002983}
2984
2985/************************************************************************
2986 * *
2987 * Routines for validity checking *
2988 * *
2989 ************************************************************************/
2990
2991/**
2992 * xmlGetDtdElementDesc:
2993 * @dtd: a pointer to the DtD to search
2994 * @name: the element name
2995 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002996 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002997 *
2998 * returns the xmlElementPtr if found or NULL
2999 */
3000
3001xmlElementPtr
3002xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3003 xmlElementTablePtr table;
3004 xmlElementPtr cur;
3005 xmlChar *uqname = NULL, *prefix = NULL;
3006
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00003007 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003008 if (dtd->elements == NULL)
3009 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003010 table = (xmlElementTablePtr) dtd->elements;
3011
3012 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003013 if (uqname != NULL)
3014 name = uqname;
3015 cur = xmlHashLookup2(table, name, prefix);
3016 if (prefix != NULL) xmlFree(prefix);
3017 if (uqname != NULL) xmlFree(uqname);
3018 return(cur);
3019}
3020/**
3021 * xmlGetDtdElementDesc2:
3022 * @dtd: a pointer to the DtD to search
3023 * @name: the element name
3024 * @create: create an empty description if not found
3025 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003026 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00003027 *
3028 * returns the xmlElementPtr if found or NULL
3029 */
3030
Daniel Veillard86fd5a72001-12-13 14:55:21 +00003031static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00003032xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3033 xmlElementTablePtr table;
3034 xmlElementPtr cur;
3035 xmlChar *uqname = NULL, *prefix = NULL;
3036
3037 if (dtd == NULL) return(NULL);
3038 if (dtd->elements == NULL) {
3039 if (!create)
3040 return(NULL);
3041 /*
3042 * Create the Element table if needed.
3043 */
3044 table = (xmlElementTablePtr) dtd->elements;
3045 if (table == NULL) {
3046 table = xmlCreateElementTable();
3047 dtd->elements = (void *) table;
3048 }
3049 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003050 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003051 return(NULL);
3052 }
3053 }
3054 table = (xmlElementTablePtr) dtd->elements;
3055
3056 uqname = xmlSplitQName2(name, &prefix);
3057 if (uqname != NULL)
3058 name = uqname;
3059 cur = xmlHashLookup2(table, name, prefix);
3060 if ((cur == NULL) && (create)) {
3061 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3062 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003063 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003064 return(NULL);
3065 }
3066 memset(cur, 0, sizeof(xmlElement));
3067 cur->type = XML_ELEMENT_DECL;
3068
3069 /*
3070 * fill the structure.
3071 */
3072 cur->name = xmlStrdup(name);
3073 cur->prefix = xmlStrdup(prefix);
3074 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3075
3076 xmlHashAddEntry2(table, name, prefix, cur);
3077 }
3078 if (prefix != NULL) xmlFree(prefix);
3079 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003080 return(cur);
3081}
3082
3083/**
3084 * xmlGetDtdQElementDesc:
3085 * @dtd: a pointer to the DtD to search
3086 * @name: the element name
3087 * @prefix: the element namespace prefix
3088 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003089 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003090 *
3091 * returns the xmlElementPtr if found or NULL
3092 */
3093
Daniel Veillard48da9102001-08-07 01:10:10 +00003094xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003095xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3096 const xmlChar *prefix) {
3097 xmlElementTablePtr table;
3098
3099 if (dtd == NULL) return(NULL);
3100 if (dtd->elements == NULL) return(NULL);
3101 table = (xmlElementTablePtr) dtd->elements;
3102
3103 return(xmlHashLookup2(table, name, prefix));
3104}
3105
3106/**
3107 * xmlGetDtdAttrDesc:
3108 * @dtd: a pointer to the DtD to search
3109 * @elem: the element name
3110 * @name: the attribute name
3111 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003112 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003113 * this element.
3114 *
3115 * returns the xmlAttributePtr if found or NULL
3116 */
3117
3118xmlAttributePtr
3119xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3120 xmlAttributeTablePtr table;
3121 xmlAttributePtr cur;
3122 xmlChar *uqname = NULL, *prefix = NULL;
3123
3124 if (dtd == NULL) return(NULL);
3125 if (dtd->attributes == NULL) return(NULL);
3126
3127 table = (xmlAttributeTablePtr) dtd->attributes;
3128 if (table == NULL)
3129 return(NULL);
3130
3131 uqname = xmlSplitQName2(name, &prefix);
3132
3133 if (uqname != NULL) {
3134 cur = xmlHashLookup3(table, uqname, prefix, elem);
3135 if (prefix != NULL) xmlFree(prefix);
3136 if (uqname != NULL) xmlFree(uqname);
3137 } else
3138 cur = xmlHashLookup3(table, name, NULL, elem);
3139 return(cur);
3140}
3141
3142/**
3143 * xmlGetDtdQAttrDesc:
3144 * @dtd: a pointer to the DtD to search
3145 * @elem: the element name
3146 * @name: the attribute name
3147 * @prefix: the attribute namespace prefix
3148 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003149 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003150 * this element.
3151 *
3152 * returns the xmlAttributePtr if found or NULL
3153 */
3154
Daniel Veillard48da9102001-08-07 01:10:10 +00003155xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003156xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3157 const xmlChar *prefix) {
3158 xmlAttributeTablePtr table;
3159
3160 if (dtd == NULL) return(NULL);
3161 if (dtd->attributes == NULL) return(NULL);
3162 table = (xmlAttributeTablePtr) dtd->attributes;
3163
3164 return(xmlHashLookup3(table, name, prefix, elem));
3165}
3166
3167/**
3168 * xmlGetDtdNotationDesc:
3169 * @dtd: a pointer to the DtD to search
3170 * @name: the notation name
3171 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003172 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003173 *
3174 * returns the xmlNotationPtr if found or NULL
3175 */
3176
3177xmlNotationPtr
3178xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3179 xmlNotationTablePtr table;
3180
3181 if (dtd == NULL) return(NULL);
3182 if (dtd->notations == NULL) return(NULL);
3183 table = (xmlNotationTablePtr) dtd->notations;
3184
3185 return(xmlHashLookup(table, name));
3186}
3187
Daniel Veillardf54cd532004-02-25 11:52:31 +00003188#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003189/**
3190 * xmlValidateNotationUse:
3191 * @ctxt: the validation context
3192 * @doc: the document
3193 * @notationName: the notation name to check
3194 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003195 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003196 * - [ VC: Notation Declared ]
3197 *
3198 * returns 1 if valid or 0 otherwise
3199 */
3200
3201int
3202xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3203 const xmlChar *notationName) {
3204 xmlNotationPtr notaDecl;
3205 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3206
3207 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3208 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3209 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3210
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003211 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003212 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3213 "NOTATION %s is not declared\n",
3214 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003215 return(0);
3216 }
3217 return(1);
3218}
Daniel Veillardf54cd532004-02-25 11:52:31 +00003219#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003220
3221/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003222 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003223 * @doc: the document
3224 * @name: the element name
3225 *
3226 * Search in the DtDs whether an element accept Mixed content (or ANY)
3227 * basically if it is supposed to accept text childs
3228 *
3229 * returns 0 if no, 1 if yes, and -1 if no element description is available
3230 */
3231
3232int
3233xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3234 xmlElementPtr elemDecl;
3235
3236 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3237
3238 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3239 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3240 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3241 if (elemDecl == NULL) return(-1);
3242 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003243 case XML_ELEMENT_TYPE_UNDEFINED:
3244 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003245 case XML_ELEMENT_TYPE_ELEMENT:
3246 return(0);
3247 case XML_ELEMENT_TYPE_EMPTY:
3248 /*
3249 * return 1 for EMPTY since we want VC error to pop up
3250 * on <empty> </empty> for example
3251 */
3252 case XML_ELEMENT_TYPE_ANY:
3253 case XML_ELEMENT_TYPE_MIXED:
3254 return(1);
3255 }
3256 return(1);
3257}
3258
Daniel Veillard4432df22003-09-28 18:58:27 +00003259#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003260/**
3261 * xmlValidateNameValue:
3262 * @value: an Name value
3263 *
3264 * Validate that the given value match Name production
3265 *
3266 * returns 1 if valid or 0 otherwise
3267 */
3268
Daniel Veillard9b731d72002-04-14 12:56:08 +00003269int
Owen Taylor3473f882001-02-23 17:55:21 +00003270xmlValidateNameValue(const xmlChar *value) {
3271 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003272 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003273
3274 if (value == NULL) return(0);
3275 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003276 val = xmlStringCurrentChar(NULL, cur, &len);
3277 cur += len;
3278 if (!IS_LETTER(val) && (val != '_') &&
3279 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003280 return(0);
3281 }
3282
Daniel Veillardd8224e02002-01-13 15:43:22 +00003283 val = xmlStringCurrentChar(NULL, cur, &len);
3284 cur += len;
3285 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3286 (val == '.') || (val == '-') ||
3287 (val == '_') || (val == ':') ||
3288 (IS_COMBINING(val)) ||
3289 (IS_EXTENDER(val))) {
3290 val = xmlStringCurrentChar(NULL, cur, &len);
3291 cur += len;
3292 }
Owen Taylor3473f882001-02-23 17:55:21 +00003293
Daniel Veillardd8224e02002-01-13 15:43:22 +00003294 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003295
3296 return(1);
3297}
3298
3299/**
3300 * xmlValidateNamesValue:
3301 * @value: an Names value
3302 *
3303 * Validate that the given value match Names production
3304 *
3305 * returns 1 if valid or 0 otherwise
3306 */
3307
Daniel Veillard9b731d72002-04-14 12:56:08 +00003308int
Owen Taylor3473f882001-02-23 17:55:21 +00003309xmlValidateNamesValue(const xmlChar *value) {
3310 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003311 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003312
3313 if (value == NULL) return(0);
3314 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003315 val = xmlStringCurrentChar(NULL, cur, &len);
3316 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003317
Daniel Veillardd8224e02002-01-13 15:43:22 +00003318 if (!IS_LETTER(val) && (val != '_') &&
3319 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003320 return(0);
3321 }
3322
Daniel Veillardd8224e02002-01-13 15:43:22 +00003323 val = xmlStringCurrentChar(NULL, cur, &len);
3324 cur += len;
3325 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3326 (val == '.') || (val == '-') ||
3327 (val == '_') || (val == ':') ||
3328 (IS_COMBINING(val)) ||
3329 (IS_EXTENDER(val))) {
3330 val = xmlStringCurrentChar(NULL, cur, &len);
3331 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003332 }
3333
Daniel Veillard807b4de2004-09-26 14:42:56 +00003334 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3335 while (val == 0x20) {
3336 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003337 val = xmlStringCurrentChar(NULL, cur, &len);
3338 cur += len;
3339 }
3340
3341 if (!IS_LETTER(val) && (val != '_') &&
3342 (val != ':')) {
3343 return(0);
3344 }
3345 val = xmlStringCurrentChar(NULL, cur, &len);
3346 cur += len;
3347
3348 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3349 (val == '.') || (val == '-') ||
3350 (val == '_') || (val == ':') ||
3351 (IS_COMBINING(val)) ||
3352 (IS_EXTENDER(val))) {
3353 val = xmlStringCurrentChar(NULL, cur, &len);
3354 cur += len;
3355 }
3356 }
3357
3358 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003359
3360 return(1);
3361}
3362
3363/**
3364 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003365 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003366 *
3367 * Validate that the given value match Nmtoken production
3368 *
3369 * [ VC: Name Token ]
3370 *
3371 * returns 1 if valid or 0 otherwise
3372 */
3373
Daniel Veillard9b731d72002-04-14 12:56:08 +00003374int
Owen Taylor3473f882001-02-23 17:55:21 +00003375xmlValidateNmtokenValue(const xmlChar *value) {
3376 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003377 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003378
3379 if (value == NULL) return(0);
3380 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003381 val = xmlStringCurrentChar(NULL, cur, &len);
3382 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003383
Daniel Veillardd8224e02002-01-13 15:43:22 +00003384 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3385 (val != '.') && (val != '-') &&
3386 (val != '_') && (val != ':') &&
3387 (!IS_COMBINING(val)) &&
3388 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003389 return(0);
3390
Daniel Veillardd8224e02002-01-13 15:43:22 +00003391 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3392 (val == '.') || (val == '-') ||
3393 (val == '_') || (val == ':') ||
3394 (IS_COMBINING(val)) ||
3395 (IS_EXTENDER(val))) {
3396 val = xmlStringCurrentChar(NULL, cur, &len);
3397 cur += len;
3398 }
Owen Taylor3473f882001-02-23 17:55:21 +00003399
Daniel Veillardd8224e02002-01-13 15:43:22 +00003400 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003401
3402 return(1);
3403}
3404
3405/**
3406 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003407 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003408 *
3409 * Validate that the given value match Nmtokens production
3410 *
3411 * [ VC: Name Token ]
3412 *
3413 * returns 1 if valid or 0 otherwise
3414 */
3415
Daniel Veillard9b731d72002-04-14 12:56:08 +00003416int
Owen Taylor3473f882001-02-23 17:55:21 +00003417xmlValidateNmtokensValue(const xmlChar *value) {
3418 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003419 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003420
3421 if (value == NULL) return(0);
3422 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003423 val = xmlStringCurrentChar(NULL, cur, &len);
3424 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003425
Daniel Veillardd8224e02002-01-13 15:43:22 +00003426 while (IS_BLANK(val)) {
3427 val = xmlStringCurrentChar(NULL, cur, &len);
3428 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003429 }
3430
Daniel Veillardd8224e02002-01-13 15:43:22 +00003431 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3432 (val != '.') && (val != '-') &&
3433 (val != '_') && (val != ':') &&
3434 (!IS_COMBINING(val)) &&
3435 (!IS_EXTENDER(val)))
3436 return(0);
3437
3438 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3439 (val == '.') || (val == '-') ||
3440 (val == '_') || (val == ':') ||
3441 (IS_COMBINING(val)) ||
3442 (IS_EXTENDER(val))) {
3443 val = xmlStringCurrentChar(NULL, cur, &len);
3444 cur += len;
3445 }
3446
Daniel Veillard807b4de2004-09-26 14:42:56 +00003447 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3448 while (val == 0x20) {
3449 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003450 val = xmlStringCurrentChar(NULL, cur, &len);
3451 cur += len;
3452 }
3453 if (val == 0) return(1);
3454
3455 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3456 (val != '.') && (val != '-') &&
3457 (val != '_') && (val != ':') &&
3458 (!IS_COMBINING(val)) &&
3459 (!IS_EXTENDER(val)))
3460 return(0);
3461
3462 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3463 (val == '.') || (val == '-') ||
3464 (val == '_') || (val == ':') ||
3465 (IS_COMBINING(val)) ||
3466 (IS_EXTENDER(val))) {
3467 val = xmlStringCurrentChar(NULL, cur, &len);
3468 cur += len;
3469 }
3470 }
3471
3472 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003473
3474 return(1);
3475}
3476
3477/**
3478 * xmlValidateNotationDecl:
3479 * @ctxt: the validation context
3480 * @doc: a document instance
3481 * @nota: a notation definition
3482 *
3483 * Try to validate a single notation definition
3484 * basically it does the following checks as described by the
3485 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003486 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003487 * But this function get called anyway ...
3488 *
3489 * returns 1 if valid or 0 otherwise
3490 */
3491
3492int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003493xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3494 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003495 int ret = 1;
3496
3497 return(ret);
3498}
3499
3500/**
3501 * xmlValidateAttributeValue:
3502 * @type: an attribute type
3503 * @value: an attribute value
3504 *
3505 * Validate that the given attribute value match the proper production
3506 *
3507 * [ VC: ID ]
3508 * Values of type ID must match the Name production....
3509 *
3510 * [ VC: IDREF ]
3511 * Values of type IDREF must match the Name production, and values
3512 * of type IDREFS must match Names ...
3513 *
3514 * [ VC: Entity Name ]
3515 * Values of type ENTITY must match the Name production, values
3516 * of type ENTITIES must match Names ...
3517 *
3518 * [ VC: Name Token ]
3519 * Values of type NMTOKEN must match the Nmtoken production; values
3520 * of type NMTOKENS must match Nmtokens.
3521 *
3522 * returns 1 if valid or 0 otherwise
3523 */
3524
3525int
3526xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3527 switch (type) {
3528 case XML_ATTRIBUTE_ENTITIES:
3529 case XML_ATTRIBUTE_IDREFS:
3530 return(xmlValidateNamesValue(value));
3531 case XML_ATTRIBUTE_ENTITY:
3532 case XML_ATTRIBUTE_IDREF:
3533 case XML_ATTRIBUTE_ID:
3534 case XML_ATTRIBUTE_NOTATION:
3535 return(xmlValidateNameValue(value));
3536 case XML_ATTRIBUTE_NMTOKENS:
3537 case XML_ATTRIBUTE_ENUMERATION:
3538 return(xmlValidateNmtokensValue(value));
3539 case XML_ATTRIBUTE_NMTOKEN:
3540 return(xmlValidateNmtokenValue(value));
3541 case XML_ATTRIBUTE_CDATA:
3542 break;
3543 }
3544 return(1);
3545}
3546
3547/**
3548 * xmlValidateAttributeValue2:
3549 * @ctxt: the validation context
3550 * @doc: the document
3551 * @name: the attribute name (used for error reporting only)
3552 * @type: the attribute type
3553 * @value: the attribute value
3554 *
3555 * Validate that the given attribute value match a given type.
3556 * This typically cannot be done before having finished parsing
3557 * the subsets.
3558 *
3559 * [ VC: IDREF ]
3560 * Values of type IDREF must match one of the declared IDs
3561 * Values of type IDREFS must match a sequence of the declared IDs
3562 * each Name must match the value of an ID attribute on some element
3563 * in the XML document; i.e. IDREF values must match the value of
3564 * some ID attribute
3565 *
3566 * [ VC: Entity Name ]
3567 * Values of type ENTITY must match one declared entity
3568 * Values of type ENTITIES must match a sequence of declared entities
3569 *
3570 * [ VC: Notation Attributes ]
3571 * all notation names in the declaration must be declared.
3572 *
3573 * returns 1 if valid or 0 otherwise
3574 */
3575
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003576static int
Owen Taylor3473f882001-02-23 17:55:21 +00003577xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3578 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3579 int ret = 1;
3580 switch (type) {
3581 case XML_ATTRIBUTE_IDREFS:
3582 case XML_ATTRIBUTE_IDREF:
3583 case XML_ATTRIBUTE_ID:
3584 case XML_ATTRIBUTE_NMTOKENS:
3585 case XML_ATTRIBUTE_ENUMERATION:
3586 case XML_ATTRIBUTE_NMTOKEN:
3587 case XML_ATTRIBUTE_CDATA:
3588 break;
3589 case XML_ATTRIBUTE_ENTITY: {
3590 xmlEntityPtr ent;
3591
3592 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003593 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003594 if ((ent == NULL) && (doc->standalone == 1)) {
3595 doc->standalone = 0;
3596 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003597 }
Owen Taylor3473f882001-02-23 17:55:21 +00003598 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003599 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3600 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003601 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003602 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003603 ret = 0;
3604 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003605 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3606 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003607 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003608 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003609 ret = 0;
3610 }
3611 break;
3612 }
3613 case XML_ATTRIBUTE_ENTITIES: {
3614 xmlChar *dup, *nam = NULL, *cur, save;
3615 xmlEntityPtr ent;
3616
3617 dup = xmlStrdup(value);
3618 if (dup == NULL)
3619 return(0);
3620 cur = dup;
3621 while (*cur != 0) {
3622 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003623 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003624 save = *cur;
3625 *cur = 0;
3626 ent = xmlGetDocEntity(doc, nam);
3627 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003628 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3629 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003630 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003631 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003632 ret = 0;
3633 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003634 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3635 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003636 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003637 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003638 ret = 0;
3639 }
3640 if (save == 0)
3641 break;
3642 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003643 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003644 }
3645 xmlFree(dup);
3646 break;
3647 }
3648 case XML_ATTRIBUTE_NOTATION: {
3649 xmlNotationPtr nota;
3650
3651 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3652 if ((nota == NULL) && (doc->extSubset != NULL))
3653 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3654
3655 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003656 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3657 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003658 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003659 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003660 ret = 0;
3661 }
3662 break;
3663 }
3664 }
3665 return(ret);
3666}
3667
3668/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003669 * xmlValidCtxtNormalizeAttributeValue:
3670 * @ctxt: the validation context
3671 * @doc: the document
3672 * @elem: the parent
3673 * @name: the attribute name
3674 * @value: the attribute value
3675 * @ctxt: the validation context or NULL
3676 *
3677 * Does the validation related extra step of the normalization of attribute
3678 * values:
3679 *
3680 * If the declared value is not CDATA, then the XML processor must further
3681 * process the normalized attribute value by discarding any leading and
3682 * trailing space (#x20) characters, and by replacing sequences of space
3683 * (#x20) characters by single space (#x20) character.
3684 *
3685 * Also check VC: Standalone Document Declaration in P32, and update
3686 * ctxt->valid accordingly
3687 *
3688 * returns a new normalized string if normalization is needed, NULL otherwise
3689 * the caller must free the returned value.
3690 */
3691
3692xmlChar *
3693xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3694 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3695 xmlChar *ret, *dst;
3696 const xmlChar *src;
3697 xmlAttributePtr attrDecl = NULL;
3698 int extsubset = 0;
3699
3700 if (doc == NULL) return(NULL);
3701 if (elem == NULL) return(NULL);
3702 if (name == NULL) return(NULL);
3703 if (value == NULL) return(NULL);
3704
3705 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003706 xmlChar fn[50];
3707 xmlChar *fullname;
3708
3709 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3710 if (fullname == NULL)
3711 return(0);
3712 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003713 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003714 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003715 if (attrDecl != NULL)
3716 extsubset = 1;
3717 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003718 if ((fullname != fn) && (fullname != elem->name))
3719 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003720 }
3721 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3722 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3723 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3724 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3725 if (attrDecl != NULL)
3726 extsubset = 1;
3727 }
3728
3729 if (attrDecl == NULL)
3730 return(NULL);
3731 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3732 return(NULL);
3733
3734 ret = xmlStrdup(value);
3735 if (ret == NULL)
3736 return(NULL);
3737 src = value;
3738 dst = ret;
3739 while (*src == 0x20) src++;
3740 while (*src != 0) {
3741 if (*src == 0x20) {
3742 while (*src == 0x20) src++;
3743 if (*src != 0)
3744 *dst++ = 0x20;
3745 } else {
3746 *dst++ = *src++;
3747 }
3748 }
3749 *dst = 0;
3750 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003751 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003752"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003753 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003754 ctxt->valid = 0;
3755 }
3756 return(ret);
3757}
3758
3759/**
Owen Taylor3473f882001-02-23 17:55:21 +00003760 * xmlValidNormalizeAttributeValue:
3761 * @doc: the document
3762 * @elem: the parent
3763 * @name: the attribute name
3764 * @value: the attribute value
3765 *
3766 * Does the validation related extra step of the normalization of attribute
3767 * values:
3768 *
3769 * If the declared value is not CDATA, then the XML processor must further
3770 * process the normalized attribute value by discarding any leading and
3771 * trailing space (#x20) characters, and by replacing sequences of space
3772 * (#x20) characters by single space (#x20) character.
3773 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003774 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003775 * the caller must free the returned value.
3776 */
3777
3778xmlChar *
3779xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3780 const xmlChar *name, const xmlChar *value) {
3781 xmlChar *ret, *dst;
3782 const xmlChar *src;
3783 xmlAttributePtr attrDecl = NULL;
3784
3785 if (doc == NULL) return(NULL);
3786 if (elem == NULL) return(NULL);
3787 if (name == NULL) return(NULL);
3788 if (value == NULL) return(NULL);
3789
3790 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003791 xmlChar fn[50];
3792 xmlChar *fullname;
3793
3794 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3795 if (fullname == NULL)
3796 return(0);
3797 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003798 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003799 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3800 if ((fullname != fn) && (fullname != elem->name))
3801 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003802 }
3803 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3804 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3805 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3806
3807 if (attrDecl == NULL)
3808 return(NULL);
3809 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3810 return(NULL);
3811
3812 ret = xmlStrdup(value);
3813 if (ret == NULL)
3814 return(NULL);
3815 src = value;
3816 dst = ret;
3817 while (*src == 0x20) src++;
3818 while (*src != 0) {
3819 if (*src == 0x20) {
3820 while (*src == 0x20) src++;
3821 if (*src != 0)
3822 *dst++ = 0x20;
3823 } else {
3824 *dst++ = *src++;
3825 }
3826 }
3827 *dst = 0;
3828 return(ret);
3829}
3830
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003831static void
Owen Taylor3473f882001-02-23 17:55:21 +00003832xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003833 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003834 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3835}
3836
3837/**
3838 * xmlValidateAttributeDecl:
3839 * @ctxt: the validation context
3840 * @doc: a document instance
3841 * @attr: an attribute definition
3842 *
3843 * Try to validate a single attribute definition
3844 * basically it does the following checks as described by the
3845 * XML-1.0 recommendation:
3846 * - [ VC: Attribute Default Legal ]
3847 * - [ VC: Enumeration ]
3848 * - [ VC: ID Attribute Default ]
3849 *
3850 * The ID/IDREF uniqueness and matching are done separately
3851 *
3852 * returns 1 if valid or 0 otherwise
3853 */
3854
3855int
3856xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3857 xmlAttributePtr attr) {
3858 int ret = 1;
3859 int val;
3860 CHECK_DTD;
3861 if(attr == NULL) return(1);
3862
3863 /* Attribute Default Legal */
3864 /* Enumeration */
3865 if (attr->defaultValue != NULL) {
3866 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3867 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003868 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003869 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003870 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003871 }
3872 ret &= val;
3873 }
3874
3875 /* ID Attribute Default */
3876 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3877 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3878 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003879 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003880 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003881 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003882 ret = 0;
3883 }
3884
3885 /* One ID per Element Type */
3886 if (attr->atype == XML_ATTRIBUTE_ID) {
3887 int nbId;
3888
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003889 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00003890 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3891 attr->elem);
3892 if (elem != NULL) {
3893 nbId = xmlScanIDAttributeDecl(NULL, elem);
3894 } else {
3895 xmlAttributeTablePtr table;
3896
3897 /*
3898 * The attribute may be declared in the internal subset and the
3899 * element in the external subset.
3900 */
3901 nbId = 0;
3902 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3903 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3904 xmlValidateAttributeIdCallback, &nbId);
3905 }
3906 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003907
3908 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003909 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3910 attr->elem, nbId, attr->name);
3911 } else if (doc->extSubset != NULL) {
3912 int extId = 0;
3913 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3914 if (elem != NULL) {
3915 extId = xmlScanIDAttributeDecl(NULL, elem);
3916 }
3917 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003918 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003919 "Element %s has %d ID attribute defined in the external subset : %s\n",
3920 attr->elem, extId, attr->name);
3921 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003922 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003923"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003924 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003925 }
3926 }
3927 }
3928
3929 /* Validity Constraint: Enumeration */
3930 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3931 xmlEnumerationPtr tree = attr->tree;
3932 while (tree != NULL) {
3933 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3934 tree = tree->next;
3935 }
3936 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003937 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003938"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003939 attr->defaultValue, attr->name, attr->elem);
3940 ret = 0;
3941 }
3942 }
3943
3944 return(ret);
3945}
3946
3947/**
3948 * xmlValidateElementDecl:
3949 * @ctxt: the validation context
3950 * @doc: a document instance
3951 * @elem: an element definition
3952 *
3953 * Try to validate a single element definition
3954 * basically it does the following checks as described by the
3955 * XML-1.0 recommendation:
3956 * - [ VC: One ID per Element Type ]
3957 * - [ VC: No Duplicate Types ]
3958 * - [ VC: Unique Element Type Declaration ]
3959 *
3960 * returns 1 if valid or 0 otherwise
3961 */
3962
3963int
3964xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3965 xmlElementPtr elem) {
3966 int ret = 1;
3967 xmlElementPtr tst;
3968
3969 CHECK_DTD;
3970
3971 if (elem == NULL) return(1);
3972
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003973#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00003974#ifdef LIBXML_REGEXP_ENABLED
3975 /* Build the regexp associated to the content model */
3976 ret = xmlValidBuildContentModel(ctxt, elem);
3977#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003978#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00003979
Owen Taylor3473f882001-02-23 17:55:21 +00003980 /* No Duplicate Types */
3981 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3982 xmlElementContentPtr cur, next;
3983 const xmlChar *name;
3984
3985 cur = elem->content;
3986 while (cur != NULL) {
3987 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3988 if (cur->c1 == NULL) break;
3989 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3990 name = cur->c1->name;
3991 next = cur->c2;
3992 while (next != NULL) {
3993 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00003994 if ((xmlStrEqual(next->name, name)) &&
3995 (xmlStrEqual(next->prefix, cur->prefix))) {
3996 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003997 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00003998 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003999 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004000 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004001 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004002 "Definition of %s has duplicate references of %s:%s\n",
4003 elem->name, cur->prefix, name);
4004 }
Owen Taylor3473f882001-02-23 17:55:21 +00004005 ret = 0;
4006 }
4007 break;
4008 }
4009 if (next->c1 == NULL) break;
4010 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00004011 if ((xmlStrEqual(next->c1->name, name)) &&
4012 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
4013 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004014 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004015 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004016 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004017 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004018 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004019 "Definition of %s has duplicate references to %s:%s\n",
4020 elem->name, cur->prefix, name);
4021 }
Owen Taylor3473f882001-02-23 17:55:21 +00004022 ret = 0;
4023 }
4024 next = next->c2;
4025 }
4026 }
4027 cur = cur->c2;
4028 }
4029 }
4030
4031 /* VC: Unique Element Type Declaration */
4032 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004033 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004034 ((tst->prefix == elem->prefix) ||
4035 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004036 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004037 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4038 "Redefinition of element %s\n",
4039 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004040 ret = 0;
4041 }
4042 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004043 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004044 ((tst->prefix == elem->prefix) ||
4045 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004046 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004047 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4048 "Redefinition of element %s\n",
4049 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004050 ret = 0;
4051 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004052 /* One ID per Element Type
4053 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004054 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4055 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004056 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004057 return(ret);
4058}
4059
4060/**
4061 * xmlValidateOneAttribute:
4062 * @ctxt: the validation context
4063 * @doc: a document instance
4064 * @elem: an element instance
4065 * @attr: an attribute instance
4066 * @value: the attribute value (without entities processing)
4067 *
4068 * Try to validate a single attribute for an element
4069 * basically it does the following checks as described by the
4070 * XML-1.0 recommendation:
4071 * - [ VC: Attribute Value Type ]
4072 * - [ VC: Fixed Attribute Default ]
4073 * - [ VC: Entity Name ]
4074 * - [ VC: Name Token ]
4075 * - [ VC: ID ]
4076 * - [ VC: IDREF ]
4077 * - [ VC: Entity Name ]
4078 * - [ VC: Notation Attributes ]
4079 *
4080 * The ID/IDREF uniqueness and matching are done separately
4081 *
4082 * returns 1 if valid or 0 otherwise
4083 */
4084
4085int
4086xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004087 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4088{
Owen Taylor3473f882001-02-23 17:55:21 +00004089 xmlAttributePtr attrDecl = NULL;
4090 int val;
4091 int ret = 1;
4092
4093 CHECK_DTD;
4094 if ((elem == NULL) || (elem->name == NULL)) return(0);
4095 if ((attr == NULL) || (attr->name == NULL)) return(0);
4096
4097 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004098 xmlChar fn[50];
4099 xmlChar *fullname;
4100
4101 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4102 if (fullname == NULL)
4103 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004104 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004105 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004106 attr->name, attr->ns->prefix);
4107 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004108 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004109 attr->name, attr->ns->prefix);
4110 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004111 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004112 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4113 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004114 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004115 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004116 if ((fullname != fn) && (fullname != elem->name))
4117 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004118 }
4119 if (attrDecl == NULL) {
4120 if (attr->ns != NULL) {
4121 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4122 attr->name, attr->ns->prefix);
4123 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4124 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4125 attr->name, attr->ns->prefix);
4126 } else {
4127 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4128 elem->name, attr->name);
4129 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4130 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4131 elem->name, attr->name);
4132 }
4133 }
4134
4135
4136 /* Validity Constraint: Attribute Value Type */
4137 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004138 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004139 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004140 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004141 return(0);
4142 }
4143 attr->atype = attrDecl->atype;
4144
4145 val = xmlValidateAttributeValue(attrDecl->atype, value);
4146 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004147 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004148 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004149 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004150 ret = 0;
4151 }
4152
4153 /* Validity constraint: Fixed Attribute Default */
4154 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4155 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004156 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004157 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004158 attr->name, elem->name, attrDecl->defaultValue);
4159 ret = 0;
4160 }
4161 }
4162
4163 /* Validity Constraint: ID uniqueness */
4164 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4165 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4166 ret = 0;
4167 }
4168
4169 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4170 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4171 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4172 ret = 0;
4173 }
4174
4175 /* Validity Constraint: Notation Attributes */
4176 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4177 xmlEnumerationPtr tree = attrDecl->tree;
4178 xmlNotationPtr nota;
4179
4180 /* First check that the given NOTATION was declared */
4181 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4182 if (nota == NULL)
4183 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4184
4185 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004186 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004187 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004188 value, attr->name, elem->name);
4189 ret = 0;
4190 }
4191
4192 /* Second, verify that it's among the list */
4193 while (tree != NULL) {
4194 if (xmlStrEqual(tree->name, value)) break;
4195 tree = tree->next;
4196 }
4197 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004198 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004199"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004200 value, attr->name, elem->name);
4201 ret = 0;
4202 }
4203 }
4204
4205 /* Validity Constraint: Enumeration */
4206 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4207 xmlEnumerationPtr tree = attrDecl->tree;
4208 while (tree != NULL) {
4209 if (xmlStrEqual(tree->name, value)) break;
4210 tree = tree->next;
4211 }
4212 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004213 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004214 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004215 value, attr->name, elem->name);
4216 ret = 0;
4217 }
4218 }
4219
4220 /* Fixed Attribute Default */
4221 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4222 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004223 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004224 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004225 attr->name, elem->name, attrDecl->defaultValue);
4226 ret = 0;
4227 }
4228
4229 /* Extra check for the attribute value */
4230 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4231 attrDecl->atype, value);
4232
4233 return(ret);
4234}
4235
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004236/**
4237 * xmlValidateOneNamespace:
4238 * @ctxt: the validation context
4239 * @doc: a document instance
4240 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004241 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004242 * @ns: an namespace declaration instance
4243 * @value: the attribute value (without entities processing)
4244 *
4245 * Try to validate a single namespace declaration for an element
4246 * basically it does the following checks as described by the
4247 * XML-1.0 recommendation:
4248 * - [ VC: Attribute Value Type ]
4249 * - [ VC: Fixed Attribute Default ]
4250 * - [ VC: Entity Name ]
4251 * - [ VC: Name Token ]
4252 * - [ VC: ID ]
4253 * - [ VC: IDREF ]
4254 * - [ VC: Entity Name ]
4255 * - [ VC: Notation Attributes ]
4256 *
4257 * The ID/IDREF uniqueness and matching are done separately
4258 *
4259 * returns 1 if valid or 0 otherwise
4260 */
4261
4262int
4263xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4264xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4265 /* xmlElementPtr elemDecl; */
4266 xmlAttributePtr attrDecl = NULL;
4267 int val;
4268 int ret = 1;
4269
4270 CHECK_DTD;
4271 if ((elem == NULL) || (elem->name == NULL)) return(0);
4272 if ((ns == NULL) || (ns->href == NULL)) return(0);
4273
4274 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004275 xmlChar fn[50];
4276 xmlChar *fullname;
4277
4278 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4279 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004280 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004281 return(0);
4282 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004283 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004284 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004285 ns->prefix, BAD_CAST "xmlns");
4286 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004287 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004288 ns->prefix, BAD_CAST "xmlns");
4289 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004290 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004291 BAD_CAST "xmlns");
4292 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004293 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004294 BAD_CAST "xmlns");
4295 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004296 if ((fullname != fn) && (fullname != elem->name))
4297 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004298 }
4299 if (attrDecl == NULL) {
4300 if (ns->prefix != NULL) {
4301 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4302 ns->prefix, BAD_CAST "xmlns");
4303 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4304 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4305 ns->prefix, BAD_CAST "xmlns");
4306 } else {
4307 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4308 elem->name, BAD_CAST "xmlns");
4309 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4310 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4311 elem->name, BAD_CAST "xmlns");
4312 }
4313 }
4314
4315
4316 /* Validity Constraint: Attribute Value Type */
4317 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004318 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004319 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004320 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004321 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004322 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004323 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004324 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004325 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004326 }
4327 return(0);
4328 }
4329
4330 val = xmlValidateAttributeValue(attrDecl->atype, value);
4331 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004332 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004333 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004334 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004335 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004336 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004337 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004338 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004339 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004340 }
4341 ret = 0;
4342 }
4343
4344 /* Validity constraint: Fixed Attribute Default */
4345 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4346 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004347 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004348 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004349 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4350 ns->prefix, elem->name, attrDecl->defaultValue);
4351 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004352 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004353 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004354 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004355 }
4356 ret = 0;
4357 }
4358 }
4359
4360 /* Validity Constraint: ID uniqueness */
4361 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4362 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4363 ret = 0;
4364 }
4365
4366 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4367 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4368 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4369 ret = 0;
4370 }
4371
4372 /* Validity Constraint: Notation Attributes */
4373 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4374 xmlEnumerationPtr tree = attrDecl->tree;
4375 xmlNotationPtr nota;
4376
4377 /* First check that the given NOTATION was declared */
4378 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4379 if (nota == NULL)
4380 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4381
4382 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004383 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004384 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004385 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4386 value, ns->prefix, elem->name);
4387 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004388 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004389 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004390 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004391 }
4392 ret = 0;
4393 }
4394
4395 /* Second, verify that it's among the list */
4396 while (tree != NULL) {
4397 if (xmlStrEqual(tree->name, value)) break;
4398 tree = tree->next;
4399 }
4400 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004401 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004402 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004403"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4404 value, ns->prefix, elem->name);
4405 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004406 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004407"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004408 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004409 }
4410 ret = 0;
4411 }
4412 }
4413
4414 /* Validity Constraint: Enumeration */
4415 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4416 xmlEnumerationPtr tree = attrDecl->tree;
4417 while (tree != NULL) {
4418 if (xmlStrEqual(tree->name, value)) break;
4419 tree = tree->next;
4420 }
4421 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004422 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004423 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004424"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4425 value, ns->prefix, elem->name);
4426 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004427 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004428"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004429 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004430 }
4431 ret = 0;
4432 }
4433 }
4434
4435 /* Fixed Attribute Default */
4436 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4437 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004438 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004439 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004440 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4441 ns->prefix, elem->name, attrDecl->defaultValue);
4442 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004443 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004444 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004445 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004446 }
4447 ret = 0;
4448 }
4449
4450 /* Extra check for the attribute value */
4451 if (ns->prefix != NULL) {
4452 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4453 attrDecl->atype, value);
4454 } else {
4455 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4456 attrDecl->atype, value);
4457 }
4458
4459 return(ret);
4460}
4461
Daniel Veillard118aed72002-09-24 14:13:13 +00004462#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004463/**
4464 * xmlValidateSkipIgnorable:
4465 * @ctxt: the validation context
4466 * @child: the child list
4467 *
4468 * Skip ignorable elements w.r.t. the validation process
4469 *
4470 * returns the first element to consider for validation of the content model
4471 */
4472
4473static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004474xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004475 while (child != NULL) {
4476 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004477 /* These things are ignored (skipped) during validation. */
4478 case XML_PI_NODE:
4479 case XML_COMMENT_NODE:
4480 case XML_XINCLUDE_START:
4481 case XML_XINCLUDE_END:
4482 child = child->next;
4483 break;
4484 case XML_TEXT_NODE:
4485 if (xmlIsBlankNode(child))
4486 child = child->next;
4487 else
4488 return(child);
4489 break;
4490 /* keep current node */
4491 default:
4492 return(child);
4493 }
4494 }
4495 return(child);
4496}
4497
4498/**
4499 * xmlValidateElementType:
4500 * @ctxt: the validation context
4501 *
4502 * Try to validate the content model of an element internal function
4503 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004504 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4505 * reference is found and -3 if the validation succeeded but
4506 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004507 */
4508
4509static int
4510xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004511 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004512 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004513
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004514 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004515 if ((NODE == NULL) && (CONT == NULL))
4516 return(1);
4517 if ((NODE == NULL) &&
4518 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4519 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4520 return(1);
4521 }
4522 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004523 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004524 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004525
4526 /*
4527 * We arrive here when more states need to be examined
4528 */
4529cont:
4530
4531 /*
4532 * We just recovered from a rollback generated by a possible
4533 * epsilon transition, go directly to the analysis phase
4534 */
4535 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004536 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004537 DEBUG_VALID_STATE(NODE, CONT)
4538 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004539 goto analyze;
4540 }
4541
4542 DEBUG_VALID_STATE(NODE, CONT)
4543 /*
4544 * we may have to save a backup state here. This is the equivalent
4545 * of handling epsilon transition in NFAs.
4546 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004547 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004548 ((CONT->parent == NULL) ||
4549 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004550 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004551 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004552 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004553 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004554 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4555 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004556 }
4557
4558
4559 /*
4560 * Check first if the content matches
4561 */
4562 switch (CONT->type) {
4563 case XML_ELEMENT_CONTENT_PCDATA:
4564 if (NODE == NULL) {
4565 DEBUG_VALID_MSG("pcdata failed no node");
4566 ret = 0;
4567 break;
4568 }
4569 if (NODE->type == XML_TEXT_NODE) {
4570 DEBUG_VALID_MSG("pcdata found, skip to next");
4571 /*
4572 * go to next element in the content model
4573 * skipping ignorable elems
4574 */
4575 do {
4576 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004577 NODE = xmlValidateSkipIgnorable(NODE);
4578 if ((NODE != NULL) &&
4579 (NODE->type == XML_ENTITY_REF_NODE))
4580 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004581 } while ((NODE != NULL) &&
4582 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004583 (NODE->type != XML_TEXT_NODE) &&
4584 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004585 ret = 1;
4586 break;
4587 } else {
4588 DEBUG_VALID_MSG("pcdata failed");
4589 ret = 0;
4590 break;
4591 }
4592 break;
4593 case XML_ELEMENT_CONTENT_ELEMENT:
4594 if (NODE == NULL) {
4595 DEBUG_VALID_MSG("element failed no node");
4596 ret = 0;
4597 break;
4598 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004599 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4600 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004601 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004602 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4603 ret = (CONT->prefix == NULL);
4604 } else if (CONT->prefix == NULL) {
4605 ret = 0;
4606 } else {
4607 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4608 }
4609 }
4610 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004611 DEBUG_VALID_MSG("element found, skip to next");
4612 /*
4613 * go to next element in the content model
4614 * skipping ignorable elems
4615 */
4616 do {
4617 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004618 NODE = xmlValidateSkipIgnorable(NODE);
4619 if ((NODE != NULL) &&
4620 (NODE->type == XML_ENTITY_REF_NODE))
4621 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004622 } while ((NODE != NULL) &&
4623 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004624 (NODE->type != XML_TEXT_NODE) &&
4625 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004626 } else {
4627 DEBUG_VALID_MSG("element failed");
4628 ret = 0;
4629 break;
4630 }
4631 break;
4632 case XML_ELEMENT_CONTENT_OR:
4633 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004634 * Small optimization.
4635 */
4636 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4637 if ((NODE == NULL) ||
4638 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4639 DEPTH++;
4640 CONT = CONT->c2;
4641 goto cont;
4642 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004643 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4644 ret = (CONT->c1->prefix == NULL);
4645 } else if (CONT->c1->prefix == NULL) {
4646 ret = 0;
4647 } else {
4648 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4649 }
4650 if (ret == 0) {
4651 DEPTH++;
4652 CONT = CONT->c2;
4653 goto cont;
4654 }
Daniel Veillard85349052001-04-20 13:48:21 +00004655 }
4656
4657 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004658 * save the second branch 'or' branch
4659 */
4660 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004661 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4662 OCCURS, ROLLBACK_OR) < 0)
4663 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004664 DEPTH++;
4665 CONT = CONT->c1;
4666 goto cont;
4667 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004668 /*
4669 * Small optimization.
4670 */
4671 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4672 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4673 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4674 if ((NODE == NULL) ||
4675 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4676 DEPTH++;
4677 CONT = CONT->c2;
4678 goto cont;
4679 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004680 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4681 ret = (CONT->c1->prefix == NULL);
4682 } else if (CONT->c1->prefix == NULL) {
4683 ret = 0;
4684 } else {
4685 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4686 }
4687 if (ret == 0) {
4688 DEPTH++;
4689 CONT = CONT->c2;
4690 goto cont;
4691 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004692 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004693 DEPTH++;
4694 CONT = CONT->c1;
4695 goto cont;
4696 }
4697
4698 /*
4699 * At this point handle going up in the tree
4700 */
4701 if (ret == -1) {
4702 DEBUG_VALID_MSG("error found returning");
4703 return(ret);
4704 }
4705analyze:
4706 while (CONT != NULL) {
4707 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004708 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004709 * this level.
4710 */
4711 if (ret == 0) {
4712 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004713 xmlNodePtr cur;
4714
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004715 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004716 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004717 DEBUG_VALID_MSG("Once branch failed, rollback");
4718 if (vstateVPop(ctxt) < 0 ) {
4719 DEBUG_VALID_MSG("exhaustion, failed");
4720 return(0);
4721 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004722 if (cur != ctxt->vstate->node)
4723 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004724 goto cont;
4725 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004726 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004727 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004728 DEBUG_VALID_MSG("Plus branch failed, rollback");
4729 if (vstateVPop(ctxt) < 0 ) {
4730 DEBUG_VALID_MSG("exhaustion, failed");
4731 return(0);
4732 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004733 if (cur != ctxt->vstate->node)
4734 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004735 goto cont;
4736 }
4737 DEBUG_VALID_MSG("Plus branch found");
4738 ret = 1;
4739 break;
4740 case XML_ELEMENT_CONTENT_MULT:
4741#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004742 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004743 DEBUG_VALID_MSG("Mult branch failed");
4744 } else {
4745 DEBUG_VALID_MSG("Mult branch found");
4746 }
4747#endif
4748 ret = 1;
4749 break;
4750 case XML_ELEMENT_CONTENT_OPT:
4751 DEBUG_VALID_MSG("Option branch failed");
4752 ret = 1;
4753 break;
4754 }
4755 } else {
4756 switch (CONT->ocur) {
4757 case XML_ELEMENT_CONTENT_OPT:
4758 DEBUG_VALID_MSG("Option branch succeeded");
4759 ret = 1;
4760 break;
4761 case XML_ELEMENT_CONTENT_ONCE:
4762 DEBUG_VALID_MSG("Once branch succeeded");
4763 ret = 1;
4764 break;
4765 case XML_ELEMENT_CONTENT_PLUS:
4766 if (STATE == ROLLBACK_PARENT) {
4767 DEBUG_VALID_MSG("Plus branch rollback");
4768 ret = 1;
4769 break;
4770 }
4771 if (NODE == NULL) {
4772 DEBUG_VALID_MSG("Plus branch exhausted");
4773 ret = 1;
4774 break;
4775 }
4776 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004777 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004778 goto cont;
4779 case XML_ELEMENT_CONTENT_MULT:
4780 if (STATE == ROLLBACK_PARENT) {
4781 DEBUG_VALID_MSG("Mult branch rollback");
4782 ret = 1;
4783 break;
4784 }
4785 if (NODE == NULL) {
4786 DEBUG_VALID_MSG("Mult branch exhausted");
4787 ret = 1;
4788 break;
4789 }
4790 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004791 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004792 goto cont;
4793 }
4794 }
4795 STATE = 0;
4796
4797 /*
4798 * Then act accordingly at the parent level
4799 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004800 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004801 if (CONT->parent == NULL)
4802 break;
4803
4804 switch (CONT->parent->type) {
4805 case XML_ELEMENT_CONTENT_PCDATA:
4806 DEBUG_VALID_MSG("Error: parent pcdata");
4807 return(-1);
4808 case XML_ELEMENT_CONTENT_ELEMENT:
4809 DEBUG_VALID_MSG("Error: parent element");
4810 return(-1);
4811 case XML_ELEMENT_CONTENT_OR:
4812 if (ret == 1) {
4813 DEBUG_VALID_MSG("Or succeeded");
4814 CONT = CONT->parent;
4815 DEPTH--;
4816 } else {
4817 DEBUG_VALID_MSG("Or failed");
4818 CONT = CONT->parent;
4819 DEPTH--;
4820 }
4821 break;
4822 case XML_ELEMENT_CONTENT_SEQ:
4823 if (ret == 0) {
4824 DEBUG_VALID_MSG("Sequence failed");
4825 CONT = CONT->parent;
4826 DEPTH--;
4827 } else if (CONT == CONT->parent->c1) {
4828 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4829 CONT = CONT->parent->c2;
4830 goto cont;
4831 } else {
4832 DEBUG_VALID_MSG("Sequence succeeded");
4833 CONT = CONT->parent;
4834 DEPTH--;
4835 }
4836 }
4837 }
4838 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004839 xmlNodePtr cur;
4840
4841 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004842 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4843 if (vstateVPop(ctxt) < 0 ) {
4844 DEBUG_VALID_MSG("exhaustion, failed");
4845 return(0);
4846 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004847 if (cur != ctxt->vstate->node)
4848 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004849 goto cont;
4850 }
4851 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004852 xmlNodePtr cur;
4853
4854 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004855 DEBUG_VALID_MSG("Failure, rollback");
4856 if (vstateVPop(ctxt) < 0 ) {
4857 DEBUG_VALID_MSG("exhaustion, failed");
4858 return(0);
4859 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004860 if (cur != ctxt->vstate->node)
4861 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004862 goto cont;
4863 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004864 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004865}
Daniel Veillard23e73572002-09-19 19:56:43 +00004866#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004867
4868/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00004869 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004870 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00004871 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004872 * @content: An element
4873 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4874 *
4875 * This will dump the list of elements to the buffer
4876 * Intended just for the debug routine
4877 */
4878static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00004879xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004880 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00004881 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004882
4883 if (node == NULL) return;
4884 if (glob) strcat(buf, "(");
4885 cur = node;
4886 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004887 len = strlen(buf);
4888 if (size - len < 50) {
4889 if ((size - len > 4) && (buf[len - 1] != '.'))
4890 strcat(buf, " ...");
4891 return;
4892 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004893 switch (cur->type) {
4894 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004895 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004896 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004897 if ((size - len > 4) && (buf[len - 1] != '.'))
4898 strcat(buf, " ...");
4899 return;
4900 }
4901 strcat(buf, (char *) cur->ns->prefix);
4902 strcat(buf, ":");
4903 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004904 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004905 if ((size - len > 4) && (buf[len - 1] != '.'))
4906 strcat(buf, " ...");
4907 return;
4908 }
4909 strcat(buf, (char *) cur->name);
4910 if (cur->next != NULL)
4911 strcat(buf, " ");
4912 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004913 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004914 if (xmlIsBlankNode(cur))
4915 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004916 case XML_CDATA_SECTION_NODE:
4917 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004918 strcat(buf, "CDATA");
4919 if (cur->next != NULL)
4920 strcat(buf, " ");
4921 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004922 case XML_ATTRIBUTE_NODE:
4923 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004924#ifdef LIBXML_DOCB_ENABLED
4925 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004926#endif
4927 case XML_HTML_DOCUMENT_NODE:
4928 case XML_DOCUMENT_TYPE_NODE:
4929 case XML_DOCUMENT_FRAG_NODE:
4930 case XML_NOTATION_NODE:
4931 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004932 strcat(buf, "???");
4933 if (cur->next != NULL)
4934 strcat(buf, " ");
4935 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004936 case XML_ENTITY_NODE:
4937 case XML_PI_NODE:
4938 case XML_DTD_NODE:
4939 case XML_COMMENT_NODE:
4940 case XML_ELEMENT_DECL:
4941 case XML_ATTRIBUTE_DECL:
4942 case XML_ENTITY_DECL:
4943 case XML_XINCLUDE_START:
4944 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004945 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004946 }
4947 cur = cur->next;
4948 }
4949 if (glob) strcat(buf, ")");
4950}
4951
4952/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004953 * xmlValidateElementContent:
4954 * @ctxt: the validation context
4955 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004956 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004957 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004958 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004959 *
4960 * Try to validate the content model of an element
4961 *
4962 * returns 1 if valid or 0 if not and -1 in case of error
4963 */
4964
4965static int
4966xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004967 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004968 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00004969#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00004970 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00004971#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00004972 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004973 xmlElementContentPtr cont;
4974 const xmlChar *name;
4975
4976 if (elemDecl == NULL)
4977 return(-1);
4978 cont = elemDecl->content;
4979 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004980
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004981#ifdef LIBXML_REGEXP_ENABLED
4982 /* Build the regexp associated to the content model */
4983 if (elemDecl->contModel == NULL)
4984 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4985 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004986 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004987 } else {
4988 xmlRegExecCtxtPtr exec;
4989
Daniel Veillardec498e12003-02-05 11:01:50 +00004990 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
4991 return(-1);
4992 }
Daniel Veillard01992e02002-10-09 10:20:30 +00004993 ctxt->nodeMax = 0;
4994 ctxt->nodeNr = 0;
4995 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004996 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4997 if (exec != NULL) {
4998 cur = child;
4999 while (cur != NULL) {
5000 switch (cur->type) {
5001 case XML_ENTITY_REF_NODE:
5002 /*
5003 * Push the current node to be able to roll back
5004 * and process within the entity
5005 */
5006 if ((cur->children != NULL) &&
5007 (cur->children->children != NULL)) {
5008 nodeVPush(ctxt, cur);
5009 cur = cur->children->children;
5010 continue;
5011 }
5012 break;
5013 case XML_TEXT_NODE:
5014 if (xmlIsBlankNode(cur))
5015 break;
5016 ret = 0;
5017 goto fail;
5018 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00005019 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005020 ret = 0;
5021 goto fail;
5022 case XML_ELEMENT_NODE:
5023 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005024 xmlChar fn[50];
5025 xmlChar *fullname;
5026
5027 fullname = xmlBuildQName(cur->name,
5028 cur->ns->prefix, fn, 50);
5029 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005030 ret = -1;
5031 goto fail;
5032 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005033 ret = xmlRegExecPushString(exec, fullname, NULL);
5034 if ((fullname != fn) && (fullname != cur->name))
5035 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005036 } else {
5037 ret = xmlRegExecPushString(exec, cur->name, NULL);
5038 }
5039 break;
5040 default:
5041 break;
5042 }
5043 /*
5044 * Switch to next element
5045 */
5046 cur = cur->next;
5047 while (cur == NULL) {
5048 cur = nodeVPop(ctxt);
5049 if (cur == NULL)
5050 break;
5051 cur = cur->next;
5052 }
5053 }
5054 ret = xmlRegExecPushString(exec, NULL, NULL);
5055fail:
5056 xmlRegFreeExecCtxt(exec);
5057 }
5058 }
5059#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005060 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005061 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005062 */
5063 ctxt->vstateMax = 8;
5064 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5065 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5066 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005067 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005068 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005069 }
5070 /*
5071 * The first entry in the stack is reserved to the current state
5072 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005073 ctxt->nodeMax = 0;
5074 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005075 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005076 ctxt->vstate = &ctxt->vstateTab[0];
5077 ctxt->vstateNr = 1;
5078 CONT = cont;
5079 NODE = child;
5080 DEPTH = 0;
5081 OCCURS = 0;
5082 STATE = 0;
5083 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005084 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005085 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5086 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005087 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005088 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005089 /*
5090 * An entities reference appeared at this level.
5091 * Buid a minimal representation of this node content
5092 * sufficient to run the validation process on it
5093 */
5094 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005095 cur = child;
5096 while (cur != NULL) {
5097 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005098 case XML_ENTITY_REF_NODE:
5099 /*
5100 * Push the current node to be able to roll back
5101 * and process within the entity
5102 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005103 if ((cur->children != NULL) &&
5104 (cur->children->children != NULL)) {
5105 nodeVPush(ctxt, cur);
5106 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005107 continue;
5108 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005109 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005110 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005111 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005112 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005113 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005114 case XML_CDATA_SECTION_NODE:
5115 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005116 case XML_ELEMENT_NODE:
5117 /*
5118 * Allocate a new node and minimally fills in
5119 * what's required
5120 */
5121 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5122 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005123 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005124 xmlFreeNodeList(repl);
5125 ret = -1;
5126 goto done;
5127 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005128 tmp->type = cur->type;
5129 tmp->name = cur->name;
5130 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005131 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005132 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005133 if (repl == NULL)
5134 repl = last = tmp;
5135 else {
5136 last->next = tmp;
5137 last = tmp;
5138 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005139 if (cur->type == XML_CDATA_SECTION_NODE) {
5140 /*
5141 * E59 spaces in CDATA does not match the
5142 * nonterminal S
5143 */
5144 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5145 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005146 break;
5147 default:
5148 break;
5149 }
5150 /*
5151 * Switch to next element
5152 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005153 cur = cur->next;
5154 while (cur == NULL) {
5155 cur = nodeVPop(ctxt);
5156 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005157 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005158 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005159 }
5160 }
5161
5162 /*
5163 * Relaunch the validation
5164 */
5165 ctxt->vstate = &ctxt->vstateTab[0];
5166 ctxt->vstateNr = 1;
5167 CONT = cont;
5168 NODE = repl;
5169 DEPTH = 0;
5170 OCCURS = 0;
5171 STATE = 0;
5172 ret = xmlValidateElementType(ctxt);
5173 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005174#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005175 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005176 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5177 char expr[5000];
5178 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005179
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005180 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005181 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005182 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005183#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005184 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005185 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005186 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005187#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005188 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005189
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005190 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005191 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5192 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5193 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005194 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005195 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5196 "Element content does not follow the DTD, expecting %s, got %s\n",
5197 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005198 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005199 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005200 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005201 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005202 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005203 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005204 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005205 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5206 "Element content does not follow the DTD\n",
5207 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005208 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005209 }
5210 ret = 0;
5211 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005212 if (ret == -3)
5213 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005214
Daniel Veillard23e73572002-09-19 19:56:43 +00005215#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005216done:
5217 /*
5218 * Deallocate the copy if done, and free up the validation stack
5219 */
5220 while (repl != NULL) {
5221 tmp = repl->next;
5222 xmlFree(repl);
5223 repl = tmp;
5224 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005225 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005226 if (ctxt->vstateTab != NULL) {
5227 xmlFree(ctxt->vstateTab);
5228 ctxt->vstateTab = NULL;
5229 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005230#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005231 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005232 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005233 if (ctxt->nodeTab != NULL) {
5234 xmlFree(ctxt->nodeTab);
5235 ctxt->nodeTab = NULL;
5236 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005237 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005238
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005239}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005240
Owen Taylor3473f882001-02-23 17:55:21 +00005241/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005242 * xmlValidateCdataElement:
5243 * @ctxt: the validation context
5244 * @doc: a document instance
5245 * @elem: an element instance
5246 *
5247 * Check that an element follows #CDATA
5248 *
5249 * returns 1 if valid or 0 otherwise
5250 */
5251static int
5252xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5253 xmlNodePtr elem) {
5254 int ret = 1;
5255 xmlNodePtr cur, child;
5256
Daniel Veillardceb09b92002-10-04 11:46:37 +00005257 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005258 return(0);
5259
5260 child = elem->children;
5261
5262 cur = child;
5263 while (cur != NULL) {
5264 switch (cur->type) {
5265 case XML_ENTITY_REF_NODE:
5266 /*
5267 * Push the current node to be able to roll back
5268 * and process within the entity
5269 */
5270 if ((cur->children != NULL) &&
5271 (cur->children->children != NULL)) {
5272 nodeVPush(ctxt, cur);
5273 cur = cur->children->children;
5274 continue;
5275 }
5276 break;
5277 case XML_COMMENT_NODE:
5278 case XML_PI_NODE:
5279 case XML_TEXT_NODE:
5280 case XML_CDATA_SECTION_NODE:
5281 break;
5282 default:
5283 ret = 0;
5284 goto done;
5285 }
5286 /*
5287 * Switch to next element
5288 */
5289 cur = cur->next;
5290 while (cur == NULL) {
5291 cur = nodeVPop(ctxt);
5292 if (cur == NULL)
5293 break;
5294 cur = cur->next;
5295 }
5296 }
5297done:
5298 ctxt->nodeMax = 0;
5299 ctxt->nodeNr = 0;
5300 if (ctxt->nodeTab != NULL) {
5301 xmlFree(ctxt->nodeTab);
5302 ctxt->nodeTab = NULL;
5303 }
5304 return(ret);
5305}
5306
5307/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005308 * xmlValidateCheckMixed:
5309 * @ctxt: the validation context
5310 * @cont: the mixed content model
5311 * @qname: the qualified name as appearing in the serialization
5312 *
5313 * Check if the given node is part of the content model.
5314 *
5315 * Returns 1 if yes, 0 if no, -1 in case of error
5316 */
5317static int
William M. Brackedb65a72004-02-06 07:36:04 +00005318xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005319 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005320 const xmlChar *name;
5321 int plen;
5322 name = xmlSplitQName3(qname, &plen);
5323
5324 if (name == NULL) {
5325 while (cont != NULL) {
5326 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5327 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5328 return(1);
5329 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5330 (cont->c1 != NULL) &&
5331 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5332 if ((cont->c1->prefix == NULL) &&
5333 (xmlStrEqual(cont->c1->name, qname)))
5334 return(1);
5335 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5336 (cont->c1 == NULL) ||
5337 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005338 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5339 "Internal: MIXED struct corrupted\n",
5340 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005341 break;
5342 }
5343 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005344 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005345 } else {
5346 while (cont != NULL) {
5347 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5348 if ((cont->prefix != NULL) &&
5349 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5350 (xmlStrEqual(cont->name, name)))
5351 return(1);
5352 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5353 (cont->c1 != NULL) &&
5354 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5355 if ((cont->c1->prefix != NULL) &&
5356 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5357 (xmlStrEqual(cont->c1->name, name)))
5358 return(1);
5359 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5360 (cont->c1 == NULL) ||
5361 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005362 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5363 "Internal: MIXED struct corrupted\n",
5364 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005365 break;
5366 }
5367 cont = cont->c2;
5368 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005369 }
5370 return(0);
5371}
5372
5373/**
5374 * xmlValidGetElemDecl:
5375 * @ctxt: the validation context
5376 * @doc: a document instance
5377 * @elem: an element instance
5378 * @extsubset: pointer, (out) indicate if the declaration was found
5379 * in the external subset.
5380 *
5381 * Finds a declaration associated to an element in the document.
5382 *
5383 * returns the pointer to the declaration or NULL if not found.
5384 */
5385static xmlElementPtr
5386xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5387 xmlNodePtr elem, int *extsubset) {
5388 xmlElementPtr elemDecl = NULL;
5389 const xmlChar *prefix = NULL;
5390
5391 if ((elem == NULL) || (elem->name == NULL)) return(NULL);
5392 if (extsubset != NULL)
5393 *extsubset = 0;
5394
5395 /*
5396 * Fetch the declaration for the qualified name
5397 */
5398 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5399 prefix = elem->ns->prefix;
5400
5401 if (prefix != NULL) {
5402 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5403 elem->name, prefix);
5404 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5405 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5406 elem->name, prefix);
5407 if ((elemDecl != NULL) && (extsubset != NULL))
5408 *extsubset = 1;
5409 }
5410 }
5411
5412 /*
5413 * Fetch the declaration for the non qualified name
5414 * This is "non-strict" validation should be done on the
5415 * full QName but in that case being flexible makes sense.
5416 */
5417 if (elemDecl == NULL) {
5418 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5419 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5420 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5421 if ((elemDecl != NULL) && (extsubset != NULL))
5422 *extsubset = 1;
5423 }
5424 }
5425 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005426 xmlErrValidNode(ctxt, elem,
5427 XML_DTD_UNKNOWN_ELEM,
5428 "No declaration for element %s\n",
5429 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005430 }
5431 return(elemDecl);
5432}
5433
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005434#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005435/**
5436 * xmlValidatePushElement:
5437 * @ctxt: the validation context
5438 * @doc: a document instance
5439 * @elem: an element instance
5440 * @qname: the qualified name as appearing in the serialization
5441 *
5442 * Push a new element start on the validation stack.
5443 *
5444 * returns 1 if no validation problem was found or 0 otherwise
5445 */
5446int
5447xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5448 xmlNodePtr elem, const xmlChar *qname) {
5449 int ret = 1;
5450 xmlElementPtr eDecl;
5451 int extsubset = 0;
5452
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005453/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005454 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5455 xmlValidStatePtr state = ctxt->vstate;
5456 xmlElementPtr elemDecl;
5457
5458 /*
5459 * Check the new element agaisnt the content model of the new elem.
5460 */
5461 if (state->elemDecl != NULL) {
5462 elemDecl = state->elemDecl;
5463
5464 switch(elemDecl->etype) {
5465 case XML_ELEMENT_TYPE_UNDEFINED:
5466 ret = 0;
5467 break;
5468 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005469 xmlErrValidNode(ctxt, state->node,
5470 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005471 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005472 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005473 ret = 0;
5474 break;
5475 case XML_ELEMENT_TYPE_ANY:
5476 /* I don't think anything is required then */
5477 break;
5478 case XML_ELEMENT_TYPE_MIXED:
5479 /* simple case of declared as #PCDATA */
5480 if ((elemDecl->content != NULL) &&
5481 (elemDecl->content->type ==
5482 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005483 xmlErrValidNode(ctxt, state->node,
5484 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005485 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005486 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005487 ret = 0;
5488 } else {
5489 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5490 qname);
5491 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005492 xmlErrValidNode(ctxt, state->node,
5493 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005494 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005495 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005496 }
5497 }
5498 break;
5499 case XML_ELEMENT_TYPE_ELEMENT:
5500 /*
5501 * TODO:
5502 * VC: Standalone Document Declaration
5503 * - element types with element content, if white space
5504 * occurs directly within any instance of those types.
5505 */
5506 if (state->exec != NULL) {
5507 ret = xmlRegExecPushString(state->exec, qname, NULL);
5508 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005509 xmlErrValidNode(ctxt, state->node,
5510 XML_DTD_CONTENT_MODEL,
5511 "Element %s content does not follow the DTD, Misplaced %s\n",
5512 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005513 ret = 0;
5514 } else {
5515 ret = 1;
5516 }
5517 }
5518 break;
5519 }
5520 }
5521 }
5522 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5523 vstateVPush(ctxt, eDecl, elem);
5524 return(ret);
5525}
5526
5527/**
5528 * xmlValidatePushCData:
5529 * @ctxt: the validation context
5530 * @data: some character data read
5531 * @len: the lenght of the data
5532 *
5533 * check the CData parsed for validation in the current stack
5534 *
5535 * returns 1 if no validation problem was found or 0 otherwise
5536 */
5537int
5538xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5539 int ret = 1;
5540
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005541/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005542 if (len <= 0)
5543 return(ret);
5544 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5545 xmlValidStatePtr state = ctxt->vstate;
5546 xmlElementPtr elemDecl;
5547
5548 /*
5549 * Check the new element agaisnt the content model of the new elem.
5550 */
5551 if (state->elemDecl != NULL) {
5552 elemDecl = state->elemDecl;
5553
5554 switch(elemDecl->etype) {
5555 case XML_ELEMENT_TYPE_UNDEFINED:
5556 ret = 0;
5557 break;
5558 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005559 xmlErrValidNode(ctxt, state->node,
5560 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005561 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005562 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005563 ret = 0;
5564 break;
5565 case XML_ELEMENT_TYPE_ANY:
5566 break;
5567 case XML_ELEMENT_TYPE_MIXED:
5568 break;
5569 case XML_ELEMENT_TYPE_ELEMENT:
5570 if (len > 0) {
5571 int i;
5572
5573 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005574 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005575 xmlErrValidNode(ctxt, state->node,
5576 XML_DTD_CONTENT_MODEL,
5577 "Element %s content does not follow the DTD, Text not allowed\n",
5578 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005579 ret = 0;
5580 goto done;
5581 }
5582 }
5583 /*
5584 * TODO:
5585 * VC: Standalone Document Declaration
5586 * element types with element content, if white space
5587 * occurs directly within any instance of those types.
5588 */
5589 }
5590 break;
5591 }
5592 }
5593 }
5594done:
5595 return(ret);
5596}
5597
5598/**
5599 * xmlValidatePopElement:
5600 * @ctxt: the validation context
5601 * @doc: a document instance
5602 * @elem: an element instance
5603 * @qname: the qualified name as appearing in the serialization
5604 *
5605 * Pop the element end from the validation stack.
5606 *
5607 * returns 1 if no validation problem was found or 0 otherwise
5608 */
5609int
5610xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005611 xmlNodePtr elem ATTRIBUTE_UNUSED,
5612 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005613 int ret = 1;
5614
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005615/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005616 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5617 xmlValidStatePtr state = ctxt->vstate;
5618 xmlElementPtr elemDecl;
5619
5620 /*
5621 * Check the new element agaisnt the content model of the new elem.
5622 */
5623 if (state->elemDecl != NULL) {
5624 elemDecl = state->elemDecl;
5625
5626 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5627 if (state->exec != NULL) {
5628 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5629 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005630 xmlErrValidNode(ctxt, state->node,
5631 XML_DTD_CONTENT_MODEL,
5632 "Element %s content does not follow the DTD, Expecting more child\n",
5633 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005634 } else {
5635 /*
5636 * previous validation errors should not generate
5637 * a new one here
5638 */
5639 ret = 1;
5640 }
5641 }
5642 }
5643 }
5644 vstateVPop(ctxt);
5645 }
5646 return(ret);
5647}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005648#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005649
5650/**
Owen Taylor3473f882001-02-23 17:55:21 +00005651 * xmlValidateOneElement:
5652 * @ctxt: the validation context
5653 * @doc: a document instance
5654 * @elem: an element instance
5655 *
5656 * Try to validate a single element and it's attributes,
5657 * basically it does the following checks as described by the
5658 * XML-1.0 recommendation:
5659 * - [ VC: Element Valid ]
5660 * - [ VC: Required Attribute ]
5661 * Then call xmlValidateOneAttribute() for each attribute present.
5662 *
5663 * The ID/IDREF checkings are done separately
5664 *
5665 * returns 1 if valid or 0 otherwise
5666 */
5667
5668int
5669xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5670 xmlNodePtr elem) {
5671 xmlElementPtr elemDecl = NULL;
5672 xmlElementContentPtr cont;
5673 xmlAttributePtr attr;
5674 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005675 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005676 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005677 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005678
5679 CHECK_DTD;
5680
5681 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005682 switch (elem->type) {
5683 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005684 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5685 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005686 return(0);
5687 case XML_TEXT_NODE:
5688 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005689 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5690 "Text element has children !\n",
5691 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005692 return(0);
5693 }
5694 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005695 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5696 "Text element has attribute !\n",
5697 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005698 return(0);
5699 }
5700 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005701 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5702 "Text element has namespace !\n",
5703 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005704 return(0);
5705 }
5706 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005707 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5708 "Text element has namespace !\n",
5709 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005710 return(0);
5711 }
5712 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005713 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5714 "Text element has no content !\n",
5715 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005716 return(0);
5717 }
5718 return(1);
5719 case XML_XINCLUDE_START:
5720 case XML_XINCLUDE_END:
5721 return(1);
5722 case XML_CDATA_SECTION_NODE:
5723 case XML_ENTITY_REF_NODE:
5724 case XML_PI_NODE:
5725 case XML_COMMENT_NODE:
5726 return(1);
5727 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005728 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5729 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005730 return(0);
5731 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005732 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5733 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005734 return(0);
5735 case XML_DOCUMENT_NODE:
5736 case XML_DOCUMENT_TYPE_NODE:
5737 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005738 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5739 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005740 return(0);
5741 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005742 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5743 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005744 return(0);
5745 case XML_ELEMENT_NODE:
5746 break;
5747 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005748 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5749 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005750 return(0);
5751 }
Owen Taylor3473f882001-02-23 17:55:21 +00005752
5753 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005754 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005755 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005756 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5757 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005758 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005759
Daniel Veillardea7751d2002-12-20 00:16:24 +00005760 /*
5761 * If vstateNr is not zero that means continuous validation is
5762 * activated, do not try to check the content model at that level.
5763 */
5764 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005765 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005766 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005767 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005768 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5769 "No declaration for element %s\n",
5770 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005771 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005772 case XML_ELEMENT_TYPE_EMPTY:
5773 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005774 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005775 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005776 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005777 ret = 0;
5778 }
5779 break;
5780 case XML_ELEMENT_TYPE_ANY:
5781 /* I don't think anything is required then */
5782 break;
5783 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005784
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005785 /* simple case of declared as #PCDATA */
5786 if ((elemDecl->content != NULL) &&
5787 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5788 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5789 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005790 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005791 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005792 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005793 }
5794 break;
5795 }
Owen Taylor3473f882001-02-23 17:55:21 +00005796 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005797 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005798 while (child != NULL) {
5799 if (child->type == XML_ELEMENT_NODE) {
5800 name = child->name;
5801 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005802 xmlChar fn[50];
5803 xmlChar *fullname;
5804
5805 fullname = xmlBuildQName(child->name, child->ns->prefix,
5806 fn, 50);
5807 if (fullname == NULL)
5808 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005809 cont = elemDecl->content;
5810 while (cont != NULL) {
5811 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005812 if (xmlStrEqual(cont->name, fullname))
5813 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005814 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5815 (cont->c1 != NULL) &&
5816 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005817 if (xmlStrEqual(cont->c1->name, fullname))
5818 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005819 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5820 (cont->c1 == NULL) ||
5821 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005822 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5823 "Internal: MIXED struct corrupted\n",
5824 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005825 break;
5826 }
5827 cont = cont->c2;
5828 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005829 if ((fullname != fn) && (fullname != child->name))
5830 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005831 if (cont != NULL)
5832 goto child_ok;
5833 }
5834 cont = elemDecl->content;
5835 while (cont != NULL) {
5836 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5837 if (xmlStrEqual(cont->name, name)) break;
5838 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5839 (cont->c1 != NULL) &&
5840 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5841 if (xmlStrEqual(cont->c1->name, name)) break;
5842 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5843 (cont->c1 == NULL) ||
5844 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005845 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5846 "Internal: MIXED struct corrupted\n",
5847 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005848 break;
5849 }
5850 cont = cont->c2;
5851 }
5852 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005853 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00005854 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005855 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005856 ret = 0;
5857 }
5858 }
5859child_ok:
5860 child = child->next;
5861 }
5862 break;
5863 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005864 if ((doc->standalone == 1) && (extsubset == 1)) {
5865 /*
5866 * VC: Standalone Document Declaration
5867 * - element types with element content, if white space
5868 * occurs directly within any instance of those types.
5869 */
5870 child = elem->children;
5871 while (child != NULL) {
5872 if (child->type == XML_TEXT_NODE) {
5873 const xmlChar *content = child->content;
5874
William M. Brack76e95df2003-10-18 16:20:14 +00005875 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005876 content++;
5877 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005878 xmlErrValidNode(ctxt, elem,
5879 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005880"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005881 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005882 ret = 0;
5883 break;
5884 }
5885 }
5886 child =child->next;
5887 }
5888 }
Owen Taylor3473f882001-02-23 17:55:21 +00005889 child = elem->children;
5890 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005891 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005892 if (tmp <= 0)
5893 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005894 break;
5895 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005896 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00005897
5898 /* [ VC: Required Attribute ] */
5899 attr = elemDecl->attributes;
5900 while (attr != NULL) {
5901 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005902 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005903
Daniel Veillarde4301c82002-02-13 13:32:35 +00005904 if ((attr->prefix == NULL) &&
5905 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5906 xmlNsPtr ns;
5907
5908 ns = elem->nsDef;
5909 while (ns != NULL) {
5910 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005911 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005912 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00005913 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005914 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5915 xmlNsPtr ns;
5916
5917 ns = elem->nsDef;
5918 while (ns != NULL) {
5919 if (xmlStrEqual(attr->name, ns->prefix))
5920 goto found;
5921 ns = ns->next;
5922 }
5923 } else {
5924 xmlAttrPtr attrib;
5925
5926 attrib = elem->properties;
5927 while (attrib != NULL) {
5928 if (xmlStrEqual(attrib->name, attr->name)) {
5929 if (attr->prefix != NULL) {
5930 xmlNsPtr nameSpace = attrib->ns;
5931
5932 if (nameSpace == NULL)
5933 nameSpace = elem->ns;
5934 /*
5935 * qualified names handling is problematic, having a
5936 * different prefix should be possible but DTDs don't
5937 * allow to define the URI instead of the prefix :-(
5938 */
5939 if (nameSpace == NULL) {
5940 if (qualified < 0)
5941 qualified = 0;
5942 } else if (!xmlStrEqual(nameSpace->prefix,
5943 attr->prefix)) {
5944 if (qualified < 1)
5945 qualified = 1;
5946 } else
5947 goto found;
5948 } else {
5949 /*
5950 * We should allow applications to define namespaces
5951 * for their application even if the DTD doesn't
5952 * carry one, otherwise, basically we would always
5953 * break.
5954 */
5955 goto found;
5956 }
5957 }
5958 attrib = attrib->next;
5959 }
Owen Taylor3473f882001-02-23 17:55:21 +00005960 }
5961 if (qualified == -1) {
5962 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005963 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005964 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005965 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005966 ret = 0;
5967 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005968 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005969 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005970 elem->name, attr->prefix,attr->name);
5971 ret = 0;
5972 }
5973 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005974 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005975 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005976 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005977 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005978 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005979 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005980 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005981 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005982 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5983 /*
5984 * Special tests checking #FIXED namespace declarations
5985 * have the right value since this is not done as an
5986 * attribute checking
5987 */
5988 if ((attr->prefix == NULL) &&
5989 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5990 xmlNsPtr ns;
5991
5992 ns = elem->nsDef;
5993 while (ns != NULL) {
5994 if (ns->prefix == NULL) {
5995 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005996 xmlErrValidNode(ctxt, elem,
5997 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00005998 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005999 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006000 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006001 }
6002 goto found;
6003 }
6004 ns = ns->next;
6005 }
6006 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6007 xmlNsPtr ns;
6008
6009 ns = elem->nsDef;
6010 while (ns != NULL) {
6011 if (xmlStrEqual(attr->name, ns->prefix)) {
6012 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006013 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006014 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006015 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006016 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006017 }
6018 goto found;
6019 }
6020 ns = ns->next;
6021 }
6022 }
Owen Taylor3473f882001-02-23 17:55:21 +00006023 }
6024found:
6025 attr = attr->nexth;
6026 }
6027 return(ret);
6028}
6029
6030/**
6031 * xmlValidateRoot:
6032 * @ctxt: the validation context
6033 * @doc: a document instance
6034 *
6035 * Try to validate a the root element
6036 * basically it does the following check as described by the
6037 * XML-1.0 recommendation:
6038 * - [ VC: Root Element Type ]
6039 * it doesn't try to recurse or apply other check to the element
6040 *
6041 * returns 1 if valid or 0 otherwise
6042 */
6043
6044int
6045xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6046 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006047 int ret;
6048
Owen Taylor3473f882001-02-23 17:55:21 +00006049 if (doc == NULL) return(0);
6050
6051 root = xmlDocGetRootElement(doc);
6052 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006053 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6054 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006055 return(0);
6056 }
6057
6058 /*
6059 * When doing post validation against a separate DTD, those may
6060 * no internal subset has been generated
6061 */
6062 if ((doc->intSubset != NULL) &&
6063 (doc->intSubset->name != NULL)) {
6064 /*
6065 * Check first the document root against the NQName
6066 */
6067 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6068 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006069 xmlChar fn[50];
6070 xmlChar *fullname;
6071
6072 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6073 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006074 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006075 return(0);
6076 }
6077 ret = xmlStrEqual(doc->intSubset->name, fullname);
6078 if ((fullname != fn) && (fullname != root->name))
6079 xmlFree(fullname);
6080 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006081 goto name_ok;
6082 }
6083 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6084 (xmlStrEqual(root->name, BAD_CAST "html")))
6085 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006086 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6087 "root and DTD name do not match '%s' and '%s'\n",
6088 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006089 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006090 }
6091 }
6092name_ok:
6093 return(1);
6094}
6095
6096
6097/**
6098 * xmlValidateElement:
6099 * @ctxt: the validation context
6100 * @doc: a document instance
6101 * @elem: an element instance
6102 *
6103 * Try to validate the subtree under an element
6104 *
6105 * returns 1 if valid or 0 otherwise
6106 */
6107
6108int
6109xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6110 xmlNodePtr child;
6111 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006112 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006113 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006114 int ret = 1;
6115
6116 if (elem == NULL) return(0);
6117
6118 /*
6119 * XInclude elements were added after parsing in the infoset,
6120 * they don't really mean anything validation wise.
6121 */
6122 if ((elem->type == XML_XINCLUDE_START) ||
6123 (elem->type == XML_XINCLUDE_END))
6124 return(1);
6125
6126 CHECK_DTD;
6127
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006128 /*
6129 * Entities references have to be handled separately
6130 */
6131 if (elem->type == XML_ENTITY_REF_NODE) {
6132 return(1);
6133 }
6134
Owen Taylor3473f882001-02-23 17:55:21 +00006135 ret &= xmlValidateOneElement(ctxt, doc, elem);
6136 attr = elem->properties;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006137 while (attr != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006138 value = xmlNodeListGetString(doc, attr->children, 0);
6139 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6140 if (value != NULL)
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006141 xmlFree((char *)value);
Owen Taylor3473f882001-02-23 17:55:21 +00006142 attr= attr->next;
6143 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006144 ns = elem->nsDef;
6145 while (ns != NULL) {
Daniel Veillard1f5c9892003-12-29 17:09:55 +00006146 if (elem->ns == NULL)
6147 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6148 ns, ns->href);
6149 else
6150 ret &= xmlValidateOneNamespace(ctxt, doc, elem, elem->ns->prefix,
6151 ns, ns->href);
Daniel Veillarde133dd82003-10-30 10:42:20 +00006152 ns = ns->next;
6153 }
Owen Taylor3473f882001-02-23 17:55:21 +00006154 child = elem->children;
6155 while (child != NULL) {
6156 ret &= xmlValidateElement(ctxt, doc, child);
6157 child = child->next;
6158 }
6159
6160 return(ret);
6161}
6162
Daniel Veillard8730c562001-02-26 10:49:57 +00006163/**
6164 * xmlValidateRef:
6165 * @ref: A reference to be validated
6166 * @ctxt: Validation context
6167 * @name: Name of ID we are searching for
6168 *
6169 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006170static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006171xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006172 const xmlChar *name) {
6173 xmlAttrPtr id;
6174 xmlAttrPtr attr;
6175
6176 if (ref == NULL)
6177 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006178 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006179 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006180 attr = ref->attr;
6181 if (attr == NULL) {
6182 xmlChar *dup, *str = NULL, *cur, save;
6183
6184 dup = xmlStrdup(name);
6185 if (dup == NULL) {
6186 ctxt->valid = 0;
6187 return;
6188 }
6189 cur = dup;
6190 while (*cur != 0) {
6191 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006192 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006193 save = *cur;
6194 *cur = 0;
6195 id = xmlGetID(ctxt->doc, str);
6196 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006197 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006198 "attribute %s line %d references an unknown ID \"%s\"\n",
6199 ref->name, ref->lineno, str);
6200 ctxt->valid = 0;
6201 }
6202 if (save == 0)
6203 break;
6204 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006205 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006206 }
6207 xmlFree(dup);
6208 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006209 id = xmlGetID(ctxt->doc, name);
6210 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006211 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006212 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006213 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006214 ctxt->valid = 0;
6215 }
6216 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6217 xmlChar *dup, *str = NULL, *cur, save;
6218
6219 dup = xmlStrdup(name);
6220 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006221 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006222 ctxt->valid = 0;
6223 return;
6224 }
6225 cur = dup;
6226 while (*cur != 0) {
6227 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006228 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006229 save = *cur;
6230 *cur = 0;
6231 id = xmlGetID(ctxt->doc, str);
6232 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006233 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006234 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006235 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006236 ctxt->valid = 0;
6237 }
6238 if (save == 0)
6239 break;
6240 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006241 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006242 }
6243 xmlFree(dup);
6244 }
6245}
6246
6247/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006248 * xmlWalkValidateList:
6249 * @data: Contents of current link
6250 * @user: Value supplied by the user
6251 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006252 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006253 */
6254static int
6255xmlWalkValidateList(const void *data, const void *user)
6256{
6257 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6258 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6259 return 1;
6260}
6261
6262/**
6263 * xmlValidateCheckRefCallback:
6264 * @ref_list: List of references
6265 * @ctxt: Validation context
6266 * @name: Name of ID we are searching for
6267 *
6268 */
6269static void
6270xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6271 const xmlChar *name) {
6272 xmlValidateMemo memo;
6273
6274 if (ref_list == NULL)
6275 return;
6276 memo.ctxt = ctxt;
6277 memo.name = name;
6278
6279 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6280
6281}
6282
6283/**
Owen Taylor3473f882001-02-23 17:55:21 +00006284 * xmlValidateDocumentFinal:
6285 * @ctxt: the validation context
6286 * @doc: a document instance
6287 *
6288 * Does the final step for the document validation once all the
6289 * incremental validation steps have been completed
6290 *
6291 * basically it does the following checks described by the XML Rec
6292 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006293 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006294 *
6295 * returns 1 if valid or 0 otherwise
6296 */
6297
6298int
6299xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6300 xmlRefTablePtr table;
6301
6302 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006303 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6304 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006305 return(0);
6306 }
6307
6308 /*
6309 * Check all the NOTATION/NOTATIONS attributes
6310 */
6311 /*
6312 * Check all the ENTITY/ENTITIES attributes definition for validity
6313 */
6314 /*
6315 * Check all the IDREF/IDREFS attributes definition for validity
6316 */
6317 table = (xmlRefTablePtr) doc->refs;
6318 ctxt->doc = doc;
6319 ctxt->valid = 1;
6320 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6321 return(ctxt->valid);
6322}
6323
6324/**
6325 * xmlValidateDtd:
6326 * @ctxt: the validation context
6327 * @doc: a document instance
6328 * @dtd: a dtd instance
6329 *
6330 * Try to validate the document against the dtd instance
6331 *
William M. Brack367df6e2004-10-23 18:14:36 +00006332 * Basically it does check all the definitions in the DtD.
6333 * Note the the internal subset (if present) is de-coupled
6334 * (i.e. not used), which could give problems if ID or IDREF
6335 * is present.
Owen Taylor3473f882001-02-23 17:55:21 +00006336 *
6337 * returns 1 if valid or 0 otherwise
6338 */
6339
6340int
6341xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6342 int ret;
William M. Brack367df6e2004-10-23 18:14:36 +00006343 xmlDtdPtr oldExt, oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006344 xmlNodePtr root;
6345
6346 if (dtd == NULL) return(0);
6347 if (doc == NULL) return(0);
6348 oldExt = doc->extSubset;
William M. Brack367df6e2004-10-23 18:14:36 +00006349 oldInt = doc->intSubset;
Owen Taylor3473f882001-02-23 17:55:21 +00006350 doc->extSubset = dtd;
William M. Brack367df6e2004-10-23 18:14:36 +00006351 doc->intSubset = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006352 ret = xmlValidateRoot(ctxt, doc);
6353 if (ret == 0) {
6354 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006355 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006356 return(ret);
6357 }
6358 if (doc->ids != NULL) {
6359 xmlFreeIDTable(doc->ids);
6360 doc->ids = NULL;
6361 }
6362 if (doc->refs != NULL) {
6363 xmlFreeRefTable(doc->refs);
6364 doc->refs = NULL;
6365 }
6366 root = xmlDocGetRootElement(doc);
6367 ret = xmlValidateElement(ctxt, doc, root);
6368 ret &= xmlValidateDocumentFinal(ctxt, doc);
6369 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006370 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006371 return(ret);
6372}
6373
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006374static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006375xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6376 const xmlChar *name ATTRIBUTE_UNUSED) {
6377 if (cur == NULL)
6378 return;
6379 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6380 xmlChar *notation = cur->content;
6381
Daniel Veillard878eab02002-02-19 13:46:09 +00006382 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006383 int ret;
6384
6385 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6386 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006387 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006388 }
6389 }
6390 }
6391}
6392
6393static void
Owen Taylor3473f882001-02-23 17:55:21 +00006394xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006395 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006396 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006397 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006398 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006399
Owen Taylor3473f882001-02-23 17:55:21 +00006400 if (cur == NULL)
6401 return;
6402 switch (cur->atype) {
6403 case XML_ATTRIBUTE_CDATA:
6404 case XML_ATTRIBUTE_ID:
6405 case XML_ATTRIBUTE_IDREF :
6406 case XML_ATTRIBUTE_IDREFS:
6407 case XML_ATTRIBUTE_NMTOKEN:
6408 case XML_ATTRIBUTE_NMTOKENS:
6409 case XML_ATTRIBUTE_ENUMERATION:
6410 break;
6411 case XML_ATTRIBUTE_ENTITY:
6412 case XML_ATTRIBUTE_ENTITIES:
6413 case XML_ATTRIBUTE_NOTATION:
6414 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006415
6416 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6417 cur->atype, cur->defaultValue);
6418 if ((ret == 0) && (ctxt->valid == 1))
6419 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006420 }
6421 if (cur->tree != NULL) {
6422 xmlEnumerationPtr tree = cur->tree;
6423 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006424 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006425 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006426 if ((ret == 0) && (ctxt->valid == 1))
6427 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006428 tree = tree->next;
6429 }
6430 }
6431 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006432 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6433 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006434 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006435 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006436 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006437 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006438 return;
6439 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006440
6441 if (doc != NULL)
6442 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6443 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006444 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006445 if ((elem == NULL) && (cur->parent != NULL) &&
6446 (cur->parent->type == XML_DTD_NODE))
6447 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006448 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006449 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006450 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006451 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006452 return;
6453 }
6454 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006455 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006456 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006457 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006458 ctxt->valid = 0;
6459 }
6460 }
Owen Taylor3473f882001-02-23 17:55:21 +00006461}
6462
6463/**
6464 * xmlValidateDtdFinal:
6465 * @ctxt: the validation context
6466 * @doc: a document instance
6467 *
6468 * Does the final step for the dtds validation once all the
6469 * subsets have been parsed
6470 *
6471 * basically it does the following checks described by the XML Rec
6472 * - check that ENTITY and ENTITIES type attributes default or
6473 * possible values matches one of the defined entities.
6474 * - check that NOTATION type attributes default or
6475 * possible values matches one of the defined notations.
6476 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006477 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006478 */
6479
6480int
6481xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006482 xmlDtdPtr dtd;
6483 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006484 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006485
6486 if (doc == NULL) return(0);
6487 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6488 return(0);
6489 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006490 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006491 dtd = doc->intSubset;
6492 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6493 table = (xmlAttributeTablePtr) dtd->attributes;
6494 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006495 }
6496 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006497 entities = (xmlEntitiesTablePtr) dtd->entities;
6498 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6499 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006500 }
6501 dtd = doc->extSubset;
6502 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6503 table = (xmlAttributeTablePtr) dtd->attributes;
6504 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006505 }
6506 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006507 entities = (xmlEntitiesTablePtr) dtd->entities;
6508 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6509 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006510 }
6511 return(ctxt->valid);
6512}
6513
6514/**
6515 * xmlValidateDocument:
6516 * @ctxt: the validation context
6517 * @doc: a document instance
6518 *
6519 * Try to validate the document instance
6520 *
6521 * basically it does the all the checks described by the XML Rec
6522 * i.e. validates the internal and external subset (if present)
6523 * and validate the document tree.
6524 *
6525 * returns 1 if valid or 0 otherwise
6526 */
6527
6528int
6529xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6530 int ret;
6531 xmlNodePtr root;
6532
Daniel Veillard2fd85422002-10-16 14:32:41 +00006533 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006534 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6535 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006536 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006537 }
Owen Taylor3473f882001-02-23 17:55:21 +00006538 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6539 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
William M. Brack8c22f9f2004-08-06 16:23:27 +00006540 xmlChar *sysID;
6541 if (doc->intSubset->SystemID != NULL) {
William M. Brackbebe7302004-08-05 06:46:47 +00006542 sysID = xmlBuildURI(doc->intSubset->SystemID,
6543 doc->URL);
William M. Brack8c22f9f2004-08-06 16:23:27 +00006544 if (sysID == NULL) {
6545 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6546 "Could not build URI for external subset \"%s\"\n",
6547 (const char *) doc->intSubset->SystemID);
6548 return 0;
6549 }
6550 } else
William M. Brackbebe7302004-08-05 06:46:47 +00006551 sysID = NULL;
William M. Brack8c22f9f2004-08-06 16:23:27 +00006552 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
William M. Brackbebe7302004-08-05 06:46:47 +00006553 (const xmlChar *)sysID);
William M. Brackbebe7302004-08-05 06:46:47 +00006554 if (sysID != NULL)
6555 xmlFree(sysID);
Owen Taylor3473f882001-02-23 17:55:21 +00006556 if (doc->extSubset == NULL) {
6557 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006558 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006559 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006560 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006561 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006562 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006563 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006564 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006565 }
6566 return(0);
6567 }
6568 }
6569
6570 if (doc->ids != NULL) {
6571 xmlFreeIDTable(doc->ids);
6572 doc->ids = NULL;
6573 }
6574 if (doc->refs != NULL) {
6575 xmlFreeRefTable(doc->refs);
6576 doc->refs = NULL;
6577 }
6578 ret = xmlValidateDtdFinal(ctxt, doc);
6579 if (!xmlValidateRoot(ctxt, doc)) return(0);
6580
6581 root = xmlDocGetRootElement(doc);
6582 ret &= xmlValidateElement(ctxt, doc, root);
6583 ret &= xmlValidateDocumentFinal(ctxt, doc);
6584 return(ret);
6585}
6586
Owen Taylor3473f882001-02-23 17:55:21 +00006587/************************************************************************
6588 * *
6589 * Routines for dynamic validation editing *
6590 * *
6591 ************************************************************************/
6592
6593/**
6594 * xmlValidGetPotentialChildren:
6595 * @ctree: an element content tree
6596 * @list: an array to store the list of child names
6597 * @len: a pointer to the number of element in the list
6598 * @max: the size of the array
6599 *
6600 * Build/extend a list of potential children allowed by the content tree
6601 *
6602 * returns the number of element in the list, or -1 in case of error.
6603 */
6604
6605int
6606xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6607 int *len, int max) {
6608 int i;
6609
6610 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6611 return(-1);
6612 if (*len >= max) return(*len);
6613
6614 switch (ctree->type) {
6615 case XML_ELEMENT_CONTENT_PCDATA:
6616 for (i = 0; i < *len;i++)
6617 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6618 list[(*len)++] = BAD_CAST "#PCDATA";
6619 break;
6620 case XML_ELEMENT_CONTENT_ELEMENT:
6621 for (i = 0; i < *len;i++)
6622 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6623 list[(*len)++] = ctree->name;
6624 break;
6625 case XML_ELEMENT_CONTENT_SEQ:
6626 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6627 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6628 break;
6629 case XML_ELEMENT_CONTENT_OR:
6630 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6631 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6632 break;
6633 }
6634
6635 return(*len);
6636}
6637
William M. Brack9333cc22004-06-24 08:33:40 +00006638/*
6639 * Dummy function to suppress messages while we try out valid elements
6640 */
6641static void xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
6642 const char *msg ATTRIBUTE_UNUSED, ...) {
6643 return;
6644}
6645
Owen Taylor3473f882001-02-23 17:55:21 +00006646/**
6647 * xmlValidGetValidElements:
6648 * @prev: an element to insert after
6649 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006650 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006651 * @max: the size of the array
6652 *
6653 * This function returns the list of authorized children to insert
6654 * within an existing tree while respecting the validity constraints
6655 * forced by the Dtd. The insertion point is defined using @prev and
6656 * @next in the following ways:
6657 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6658 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6659 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6660 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6661 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6662 *
6663 * pointers to the element names are inserted at the beginning of the array
6664 * and do not need to be freed.
6665 *
6666 * returns the number of element in the list, or -1 in case of error. If
6667 * the function returns the value @max the caller is invited to grow the
6668 * receiving array and retry.
6669 */
6670
6671int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006672xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006673 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006674 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006675 int nb_valid_elements = 0;
6676 const xmlChar *elements[256];
6677 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006678 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006679
6680 xmlNode *ref_node;
6681 xmlNode *parent;
6682 xmlNode *test_node;
6683
6684 xmlNode *prev_next;
6685 xmlNode *next_prev;
6686 xmlNode *parent_childs;
6687 xmlNode *parent_last;
6688
6689 xmlElement *element_desc;
6690
6691 if (prev == NULL && next == NULL)
6692 return(-1);
6693
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006694 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006695 if (max <= 0) return(-1);
6696
William M. Brack9333cc22004-06-24 08:33:40 +00006697 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6698 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6699
Owen Taylor3473f882001-02-23 17:55:21 +00006700 nb_valid_elements = 0;
6701 ref_node = prev ? prev : next;
6702 parent = ref_node->parent;
6703
6704 /*
6705 * Retrieves the parent element declaration
6706 */
6707 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6708 parent->name);
6709 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6710 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6711 parent->name);
6712 if (element_desc == NULL) return(-1);
6713
6714 /*
6715 * Do a backup of the current tree structure
6716 */
6717 prev_next = prev ? prev->next : NULL;
6718 next_prev = next ? next->prev : NULL;
6719 parent_childs = parent->children;
6720 parent_last = parent->last;
6721
6722 /*
6723 * Creates a dummy node and insert it into the tree
6724 */
Daniel Veillard95ddcd32004-10-26 21:53:55 +00006725 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006726 test_node->parent = parent;
6727 test_node->prev = prev;
6728 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006729 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006730
6731 if (prev) prev->next = test_node;
6732 else parent->children = test_node;
6733
6734 if (next) next->prev = test_node;
6735 else parent->last = test_node;
6736
6737 /*
6738 * Insert each potential child node and check if the parent is
6739 * still valid
6740 */
6741 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6742 elements, &nb_elements, 256);
6743
6744 for (i = 0;i < nb_elements;i++) {
6745 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006746 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006747 int j;
6748
6749 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006750 if (xmlStrEqual(elements[i], names[j])) break;
6751 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00006752 if (nb_valid_elements >= max) break;
6753 }
6754 }
6755
6756 /*
6757 * Restore the tree structure
6758 */
6759 if (prev) prev->next = prev_next;
6760 if (next) next->prev = next_prev;
6761 parent->children = parent_childs;
6762 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006763
6764 /*
6765 * Free up the dummy node
6766 */
6767 test_node->name = name;
6768 xmlFreeNode(test_node);
6769
Owen Taylor3473f882001-02-23 17:55:21 +00006770 return(nb_valid_elements);
6771}
Daniel Veillard4432df22003-09-28 18:58:27 +00006772#endif /* LIBXML_VALID_ENABLED */
6773