blob: 975ed9feb1947d159074fbf9af78a73ecc6b866c [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * valid.c : part of the code use to do the DTD handling and the validity
3 * checking
4 *
5 * See Copyright for the status of this software.
6 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00007 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00008 */
9
Daniel Veillard34ce8be2002-03-18 19:37:11 +000010#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000011#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000012
Owen Taylor3473f882001-02-23 17:55:21 +000013#include <string.h>
14
15#ifdef HAVE_STDLIB_H
16#include <stdlib.h>
17#endif
18
19#include <libxml/xmlmemory.h>
20#include <libxml/hash.h>
Daniel Veillard29b17482004-08-16 00:39:03 +000021#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <libxml/valid.h>
23#include <libxml/parser.h>
24#include <libxml/parserInternals.h>
25#include <libxml/xmlerror.h>
26#include <libxml/list.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000027#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000028
Daniel Veillard4432df22003-09-28 18:58:27 +000029static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
30 int create);
Daniel Veillarde62d36c2001-05-15 08:53:16 +000031/* #define DEBUG_VALID_ALGO */
Daniel Veillard5acfd6b2002-09-18 16:29:02 +000032/* #define DEBUG_REGEXP_ALGO */
Daniel Veillarde62d36c2001-05-15 08:53:16 +000033
Daniel Veillarda646cfd2002-09-17 21:50:03 +000034#define TODO \
35 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
37 __FILE__, __LINE__);
Owen Taylor3473f882001-02-23 17:55:21 +000038
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000039/************************************************************************
40 * *
41 * Error handling routines *
42 * *
43 ************************************************************************/
44
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000045/**
Daniel Veillardce9457f2003-10-05 21:33:18 +000046 * xmlVErrMemory:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000047 * @ctxt: an XML validation parser context
48 * @extra: extra informations
49 *
50 * Handle an out of memory error
51 */
52static void
Daniel Veillardce9457f2003-10-05 21:33:18 +000053xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000054{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000055 xmlGenericErrorFunc channel = NULL;
56 xmlParserCtxtPtr pctxt = NULL;
57 void *data = NULL;
58
59 if (ctxt != NULL) {
60 channel = ctxt->error;
61 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +000062 /* Use the special values to detect if it is part of a parsing
63 context */
64 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
65 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
66 pctxt = ctxt->userData;
67 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +000068 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000069 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000070 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000071 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000072 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
73 "Memory allocation failed : %s\n", extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000074 else
Daniel Veillard73000572003-10-11 11:26:42 +000075 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000076 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000077 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
78 "Memory allocation failed\n");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000079}
80
81/**
82 * xmlErrValid:
83 * @ctxt: an XML validation parser context
Daniel Veillardbb5abab2003-10-03 22:21:51 +000084 * @error: the error number
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000085 * @extra: extra informations
86 *
87 * Handle a validation error
88 */
89static void
Daniel Veillardf88d8cf2003-12-08 10:25:02 +000090xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000091 const char *msg, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000092{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000093 xmlGenericErrorFunc channel = NULL;
94 xmlParserCtxtPtr pctxt = NULL;
95 void *data = NULL;
96
97 if (ctxt != NULL) {
98 channel = ctxt->error;
99 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000100 /* Use the special values to detect if it is part of a parsing
101 context */
102 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
103 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
104 pctxt = ctxt->userData;
105 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000106 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000107 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +0000108 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000109 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000110 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
111 msg, extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000112 else
Daniel Veillard73000572003-10-11 11:26:42 +0000113 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000114 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000115 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
116 msg);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000117}
118
Daniel Veillardf54cd532004-02-25 11:52:31 +0000119#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
120/**
121 * xmlErrValidNode:
122 * @ctxt: an XML validation parser context
123 * @node: the node raising the error
124 * @error: the error number
125 * @str1: extra informations
126 * @str2: extra informations
127 * @str3: extra informations
128 *
129 * Handle a validation error, provide contextual informations
130 */
131static void
132xmlErrValidNode(xmlValidCtxtPtr ctxt,
133 xmlNodePtr node, xmlParserErrors error,
134 const char *msg, const xmlChar * str1,
135 const xmlChar * str2, const xmlChar * str3)
136{
137 xmlStructuredErrorFunc schannel = NULL;
138 xmlGenericErrorFunc channel = NULL;
139 xmlParserCtxtPtr pctxt = NULL;
140 void *data = NULL;
141
142 if (ctxt != NULL) {
143 channel = ctxt->error;
144 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000145 /* Use the special values to detect if it is part of a parsing
146 context */
147 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
148 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
149 pctxt = ctxt->userData;
150 }
Daniel Veillardf54cd532004-02-25 11:52:31 +0000151 }
152 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
153 XML_ERR_ERROR, NULL, 0,
154 (const char *) str1,
155 (const char *) str1,
156 (const char *) str3, 0, 0, msg, str1, str2, str3);
157}
158#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
159
Daniel Veillardd61e8fb2003-10-19 21:59:17 +0000160#ifdef LIBXML_VALID_ENABLED
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000161/**
162 * xmlErrValidNodeNr:
163 * @ctxt: an XML validation parser context
164 * @node: the node raising the error
165 * @error: the error number
166 * @str1: extra informations
167 * @int2: extra informations
168 * @str3: extra informations
169 *
170 * Handle a validation error, provide contextual informations
171 */
172static void
Daniel Veillard72b9e292003-10-28 15:44:17 +0000173xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000174 xmlNodePtr node, xmlParserErrors error,
175 const char *msg, const xmlChar * str1,
176 int int2, const xmlChar * str3)
177{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000178 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000179 xmlGenericErrorFunc channel = NULL;
180 xmlParserCtxtPtr pctxt = NULL;
181 void *data = NULL;
182
183 if (ctxt != NULL) {
184 channel = ctxt->error;
185 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000186 /* Use the special values to detect if it is part of a parsing
187 context */
188 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
189 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
190 pctxt = ctxt->userData;
191 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000192 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000193 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000194 XML_ERR_ERROR, NULL, 0,
195 (const char *) str1,
196 (const char *) str3,
197 NULL, int2, 0, msg, str1, int2, str3);
198}
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000199
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000200/**
201 * xmlErrValidWarning:
202 * @ctxt: an XML validation parser context
203 * @node: the node raising the error
204 * @error: the error number
William M. Brackedb65a72004-02-06 07:36:04 +0000205 * @str1: extra information
206 * @str2: extra information
207 * @str3: extra information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000208 *
William M. Brackedb65a72004-02-06 07:36:04 +0000209 * Handle a validation error, provide contextual information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000210 */
211static void
William M. Brackedb65a72004-02-06 07:36:04 +0000212xmlErrValidWarning(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000213 xmlNodePtr node, xmlParserErrors error,
214 const char *msg, const xmlChar * str1,
215 const xmlChar * str2, const xmlChar * str3)
216{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000217 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000218 xmlGenericErrorFunc channel = NULL;
219 xmlParserCtxtPtr pctxt = NULL;
220 void *data = NULL;
221
222 if (ctxt != NULL) {
William M. Bracke4d526f2004-12-18 00:01:21 +0000223 channel = ctxt->warning;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000224 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000225 /* Use the special values to detect if it is part of a parsing
226 context */
227 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
228 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
229 pctxt = ctxt->userData;
230 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000231 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000232 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000233 XML_ERR_WARNING, NULL, 0,
234 (const char *) str1,
235 (const char *) str1,
236 (const char *) str3, 0, 0, msg, str1, str2, str3);
237}
238
239
Daniel Veillardea7751d2002-12-20 00:16:24 +0000240
241#ifdef LIBXML_REGEXP_ENABLED
242/*
243 * If regexp are enabled we can do continuous validation without the
244 * need of a tree to validate the content model. this is done in each
245 * callbacks.
246 * Each xmlValidState represent the validation state associated to the
247 * set of nodes currently open from the document root to the current element.
248 */
249
250
251typedef struct _xmlValidState {
252 xmlElementPtr elemDecl; /* pointer to the content model */
253 xmlNodePtr node; /* pointer to the current node */
254 xmlRegExecCtxtPtr exec; /* regexp runtime */
255} _xmlValidState;
256
257
258static int
259vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000260 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000261 ctxt->vstateMax = 10;
262 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
263 sizeof(ctxt->vstateTab[0]));
264 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000265 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000266 return(-1);
267 }
268 }
269
270 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000271 xmlValidState *tmp;
272
273 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
274 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
275 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000276 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000277 return(-1);
278 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000279 ctxt->vstateMax *= 2;
280 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000281 }
282 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
283 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
284 ctxt->vstateTab[ctxt->vstateNr].node = node;
285 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
286 if (elemDecl->contModel == NULL)
287 xmlValidBuildContentModel(ctxt, elemDecl);
288 if (elemDecl->contModel != NULL) {
289 ctxt->vstateTab[ctxt->vstateNr].exec =
290 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
291 } else {
292 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000293 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
294 XML_ERR_INTERNAL_ERROR,
295 "Failed to build content model regexp for %s\n",
296 node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000297 }
298 }
299 return(ctxt->vstateNr++);
300}
301
302static int
303vstateVPop(xmlValidCtxtPtr ctxt) {
304 xmlElementPtr elemDecl;
305
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000306 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000307 ctxt->vstateNr--;
308 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
309 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
310 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
311 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
312 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
313 }
314 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
315 if (ctxt->vstateNr >= 1)
316 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
317 else
318 ctxt->vstate = NULL;
319 return(ctxt->vstateNr);
320}
321
322#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000323/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000324 * If regexp are not enabled, it uses a home made algorithm less
325 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000326 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000327 * only restriction is on the deepness of the tree limited by the
328 * size of the occurs bitfield
329 *
330 * this is the content of a saved state for rollbacks
331 */
332
333#define ROLLBACK_OR 0
334#define ROLLBACK_PARENT 1
335
Daniel Veillardb44025c2001-10-11 22:55:55 +0000336typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000337 xmlElementContentPtr cont; /* pointer to the content model subtree */
338 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000339 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000340 unsigned char depth; /* current depth in the overall tree */
341 unsigned char state; /* ROLLBACK_XXX */
342} _xmlValidState;
343
Daniel Veillardfc57b412002-04-29 15:50:14 +0000344#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000345#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
346#define CONT ctxt->vstate->cont
347#define NODE ctxt->vstate->node
348#define DEPTH ctxt->vstate->depth
349#define OCCURS ctxt->vstate->occurs
350#define STATE ctxt->vstate->state
351
Daniel Veillard5344c602001-12-31 16:37:34 +0000352#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
353#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000354
Daniel Veillard5344c602001-12-31 16:37:34 +0000355#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
356#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000357
358static int
359vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
360 xmlNodePtr node, unsigned char depth, long occurs,
361 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000362 int i = ctxt->vstateNr - 1;
363
Daniel Veillard940492d2002-04-15 10:15:25 +0000364 if (ctxt->vstateNr > MAX_RECURSE) {
365 return(-1);
366 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000367 if (ctxt->vstateTab == NULL) {
368 ctxt->vstateMax = 8;
369 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
370 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
371 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000372 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000373 return(-1);
374 }
375 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000376 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000377 xmlValidState *tmp;
378
379 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
380 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
381 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000382 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000383 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000384 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000385 ctxt->vstateMax *= 2;
386 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000387 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000388 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000389 /*
390 * Don't push on the stack a state already here
391 */
392 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
393 (ctxt->vstateTab[i].node == node) &&
394 (ctxt->vstateTab[i].depth == depth) &&
395 (ctxt->vstateTab[i].occurs == occurs) &&
396 (ctxt->vstateTab[i].state == state))
397 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000398 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
399 ctxt->vstateTab[ctxt->vstateNr].node = node;
400 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
401 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
402 ctxt->vstateTab[ctxt->vstateNr].state = state;
403 return(ctxt->vstateNr++);
404}
405
406static int
407vstateVPop(xmlValidCtxtPtr ctxt) {
408 if (ctxt->vstateNr <= 1) return(-1);
409 ctxt->vstateNr--;
410 ctxt->vstate = &ctxt->vstateTab[0];
411 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
412 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
413 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
414 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
415 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
416 return(ctxt->vstateNr);
417}
418
Daniel Veillard118aed72002-09-24 14:13:13 +0000419#endif /* LIBXML_REGEXP_ENABLED */
420
Daniel Veillard1c732d22002-11-30 11:22:59 +0000421static int
422nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
423{
424 if (ctxt->nodeMax <= 0) {
425 ctxt->nodeMax = 4;
426 ctxt->nodeTab =
427 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
428 sizeof(ctxt->nodeTab[0]));
429 if (ctxt->nodeTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000430 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000431 ctxt->nodeMax = 0;
432 return (0);
433 }
434 }
435 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000436 xmlNodePtr *tmp;
437 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
438 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
439 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000440 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000441 return (0);
442 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000443 ctxt->nodeMax *= 2;
444 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000445 }
446 ctxt->nodeTab[ctxt->nodeNr] = value;
447 ctxt->node = value;
448 return (ctxt->nodeNr++);
449}
450static xmlNodePtr
451nodeVPop(xmlValidCtxtPtr ctxt)
452{
453 xmlNodePtr ret;
454
455 if (ctxt->nodeNr <= 0)
456 return (0);
457 ctxt->nodeNr--;
458 if (ctxt->nodeNr > 0)
459 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
460 else
461 ctxt->node = NULL;
462 ret = ctxt->nodeTab[ctxt->nodeNr];
463 ctxt->nodeTab[ctxt->nodeNr] = 0;
464 return (ret);
465}
Owen Taylor3473f882001-02-23 17:55:21 +0000466
Owen Taylor3473f882001-02-23 17:55:21 +0000467#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000468static void
469xmlValidPrintNode(xmlNodePtr cur) {
470 if (cur == NULL) {
471 xmlGenericError(xmlGenericErrorContext, "null");
472 return;
473 }
474 switch (cur->type) {
475 case XML_ELEMENT_NODE:
476 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
477 break;
478 case XML_TEXT_NODE:
479 xmlGenericError(xmlGenericErrorContext, "text ");
480 break;
481 case XML_CDATA_SECTION_NODE:
482 xmlGenericError(xmlGenericErrorContext, "cdata ");
483 break;
484 case XML_ENTITY_REF_NODE:
485 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
486 break;
487 case XML_PI_NODE:
488 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
489 break;
490 case XML_COMMENT_NODE:
491 xmlGenericError(xmlGenericErrorContext, "comment ");
492 break;
493 case XML_ATTRIBUTE_NODE:
494 xmlGenericError(xmlGenericErrorContext, "?attr? ");
495 break;
496 case XML_ENTITY_NODE:
497 xmlGenericError(xmlGenericErrorContext, "?ent? ");
498 break;
499 case XML_DOCUMENT_NODE:
500 xmlGenericError(xmlGenericErrorContext, "?doc? ");
501 break;
502 case XML_DOCUMENT_TYPE_NODE:
503 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
504 break;
505 case XML_DOCUMENT_FRAG_NODE:
506 xmlGenericError(xmlGenericErrorContext, "?frag? ");
507 break;
508 case XML_NOTATION_NODE:
509 xmlGenericError(xmlGenericErrorContext, "?nota? ");
510 break;
511 case XML_HTML_DOCUMENT_NODE:
512 xmlGenericError(xmlGenericErrorContext, "?html? ");
513 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000514#ifdef LIBXML_DOCB_ENABLED
515 case XML_DOCB_DOCUMENT_NODE:
516 xmlGenericError(xmlGenericErrorContext, "?docb? ");
517 break;
518#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000519 case XML_DTD_NODE:
520 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
521 break;
522 case XML_ELEMENT_DECL:
523 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
524 break;
525 case XML_ATTRIBUTE_DECL:
526 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
527 break;
528 case XML_ENTITY_DECL:
529 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
530 break;
531 case XML_NAMESPACE_DECL:
532 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
533 break;
534 case XML_XINCLUDE_START:
535 xmlGenericError(xmlGenericErrorContext, "incstart ");
536 break;
537 case XML_XINCLUDE_END:
538 xmlGenericError(xmlGenericErrorContext, "incend ");
539 break;
540 }
541}
542
543static void
544xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000545 if (cur == NULL)
546 xmlGenericError(xmlGenericErrorContext, "null ");
547 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000548 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000549 cur = cur->next;
550 }
551}
552
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000553static void
554xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000555 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000556
557 expr[0] = 0;
558 xmlGenericError(xmlGenericErrorContext, "valid: ");
559 xmlValidPrintNodeList(cur);
560 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000561 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000562 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
563}
564
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000565static void
566xmlValidDebugState(xmlValidStatePtr state) {
567 xmlGenericError(xmlGenericErrorContext, "(");
568 if (state->cont == NULL)
569 xmlGenericError(xmlGenericErrorContext, "null,");
570 else
571 switch (state->cont->type) {
572 case XML_ELEMENT_CONTENT_PCDATA:
573 xmlGenericError(xmlGenericErrorContext, "pcdata,");
574 break;
575 case XML_ELEMENT_CONTENT_ELEMENT:
576 xmlGenericError(xmlGenericErrorContext, "%s,",
577 state->cont->name);
578 break;
579 case XML_ELEMENT_CONTENT_SEQ:
580 xmlGenericError(xmlGenericErrorContext, "seq,");
581 break;
582 case XML_ELEMENT_CONTENT_OR:
583 xmlGenericError(xmlGenericErrorContext, "or,");
584 break;
585 }
586 xmlValidPrintNode(state->node);
587 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
588 state->depth, state->occurs, state->state);
589}
590
591static void
592xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
593 int i, j;
594
595 xmlGenericError(xmlGenericErrorContext, "state: ");
596 xmlValidDebugState(ctxt->vstate);
597 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
598 ctxt->vstateNr - 1);
599 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
600 xmlValidDebugState(&ctxt->vstateTab[j]);
601 xmlGenericError(xmlGenericErrorContext, "\n");
602}
603
604/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000605#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000606 *****/
607
608#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000609#define DEBUG_VALID_MSG(m) \
610 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
611
Owen Taylor3473f882001-02-23 17:55:21 +0000612#else
613#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000614#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000615#endif
616
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000617/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000618
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000619
Owen Taylor3473f882001-02-23 17:55:21 +0000620#define CHECK_DTD \
621 if (doc == NULL) return(0); \
622 else if ((doc->intSubset == NULL) && \
623 (doc->extSubset == NULL)) return(0)
624
Owen Taylor3473f882001-02-23 17:55:21 +0000625xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
626
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000627#ifdef LIBXML_REGEXP_ENABLED
628
629/************************************************************************
630 * *
631 * Content model validation based on the regexps *
632 * *
633 ************************************************************************/
634
635/**
636 * xmlValidBuildAContentModel:
637 * @content: the content model
638 * @ctxt: the schema parser context
639 * @name: the element name whose content is being built
640 *
641 * Generate the automata sequence needed for that type
642 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000643 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000644 */
645static int
646xmlValidBuildAContentModel(xmlElementContentPtr content,
647 xmlValidCtxtPtr ctxt,
648 const xmlChar *name) {
649 if (content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000650 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
651 "Found NULL content in content model of %s\n",
652 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000653 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000654 }
655 switch (content->type) {
656 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000657 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
658 "Found PCDATA in content model of %s\n",
659 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000660 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000661 break;
662 case XML_ELEMENT_CONTENT_ELEMENT: {
663 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000664 xmlChar fn[50];
665 xmlChar *fullname;
666
667 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
668 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000669 xmlVErrMemory(ctxt, "Building content model");
Daniel Veillardc00cda82003-04-07 10:22:39 +0000670 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000671 }
672
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000673 switch (content->ocur) {
674 case XML_ELEMENT_CONTENT_ONCE:
675 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000676 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000677 break;
678 case XML_ELEMENT_CONTENT_OPT:
679 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000680 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000681 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
682 break;
683 case XML_ELEMENT_CONTENT_PLUS:
684 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000685 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000686 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000687 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000688 break;
689 case XML_ELEMENT_CONTENT_MULT:
William M. Brack8b0cbb02004-04-17 13:31:06 +0000690 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
691 ctxt->state, NULL);
692 xmlAutomataNewTransition(ctxt->am,
693 ctxt->state, ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000694 break;
695 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000696 if ((fullname != fn) && (fullname != content->name))
697 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000698 break;
699 }
700 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000701 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000702 xmlElementContentOccur ocur;
703
704 /*
705 * Simply iterate over the content
706 */
707 oldstate = ctxt->state;
708 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000709 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
710 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
711 oldstate = ctxt->state;
712 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000713 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000714 xmlValidBuildAContentModel(content->c1, ctxt, name);
715 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000716 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
717 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
718 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000719 oldend = ctxt->state;
720 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000721 switch (ocur) {
722 case XML_ELEMENT_CONTENT_ONCE:
723 break;
724 case XML_ELEMENT_CONTENT_OPT:
725 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
726 break;
727 case XML_ELEMENT_CONTENT_MULT:
728 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000729 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000730 break;
731 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000732 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000733 break;
734 }
735 break;
736 }
737 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000738 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000739 xmlElementContentOccur ocur;
740
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000741 ocur = content->ocur;
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000742 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
743 (ocur == XML_ELEMENT_CONTENT_MULT)) {
744 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
745 ctxt->state, NULL);
746 }
747 oldstate = ctxt->state;
748 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000749
750 /*
751 * iterate over the subtypes and remerge the end with an
752 * epsilon transition
753 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000754 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000755 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000756 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000757 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000758 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000759 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
760 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000761 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000762 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000763 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
764 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000765 switch (ocur) {
766 case XML_ELEMENT_CONTENT_ONCE:
767 break;
768 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000769 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000770 break;
771 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000772 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
773 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000774 break;
775 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000776 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000777 break;
778 }
779 break;
780 }
781 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000782 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
783 "ContentModel broken for element %s\n",
784 (const char *) name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000785 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000786 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000787 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000788}
789/**
790 * xmlValidBuildContentModel:
791 * @ctxt: a validation context
792 * @elem: an element declaration node
793 *
794 * (Re)Build the automata associated to the content model of this
795 * element
796 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000797 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000798 */
799int
800xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000801
802 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000803 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000804 if (elem->type != XML_ELEMENT_DECL)
805 return(0);
806 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
807 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000808 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000809 if (elem->contModel != NULL) {
810 if (!xmlRegexpIsDeterminist(elem->contModel)) {
811 ctxt->valid = 0;
812 return(0);
813 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000814 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000815 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000816
817 ctxt->am = xmlNewAutomata();
818 if (ctxt->am == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000819 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
820 XML_ERR_INTERNAL_ERROR,
821 "Cannot create automata for element %s\n",
822 elem->name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000823 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000824 }
William M. Brack78637da2003-07-31 14:47:38 +0000825 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000826 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
827 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000828 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000829 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000830 char expr[5000];
831 expr[0] = 0;
832 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000833 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
834 XML_DTD_CONTENT_NOT_DETERMINIST,
835 "Content model of %s is not determinist: %s\n",
836 elem->name, BAD_CAST expr, NULL);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000837#ifdef DEBUG_REGEXP_ALGO
838 xmlRegexpPrint(stderr, elem->contModel);
839#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000840 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000841 ctxt->state = NULL;
842 xmlFreeAutomata(ctxt->am);
843 ctxt->am = NULL;
844 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000845 }
846 ctxt->state = NULL;
847 xmlFreeAutomata(ctxt->am);
848 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000849 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000850}
851
852#endif /* LIBXML_REGEXP_ENABLED */
853
Owen Taylor3473f882001-02-23 17:55:21 +0000854/****************************************************************
855 * *
856 * Util functions for data allocation/deallocation *
857 * *
858 ****************************************************************/
859
860/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000861 * xmlNewValidCtxt:
862 *
863 * Allocate a validation context structure.
864 *
865 * Returns NULL if not, otherwise the new validation context structure
866 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000867xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000868 xmlValidCtxtPtr ret;
869
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000870 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000871 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000872 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000873 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000874
875 (void) memset(ret, 0, sizeof (xmlValidCtxt));
876
877 return (ret);
878}
879
880/**
881 * xmlFreeValidCtxt:
882 * @cur: the validation context to free
883 *
884 * Free a validation context structure.
885 */
886void
887xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
Daniel Veillardc0be74b2004-11-03 19:16:55 +0000888 if (cur->vstateTab != NULL)
889 xmlFree(cur->vstateTab);
890 if (cur->nodeTab != NULL)
891 xmlFree(cur->nodeTab);
Daniel Veillarda37aab82003-06-09 09:10:36 +0000892 xmlFree(cur);
893}
894
Daniel Veillard4432df22003-09-28 18:58:27 +0000895#endif /* LIBXML_VALID_ENABLED */
896
Daniel Veillarda37aab82003-06-09 09:10:36 +0000897/**
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000898 * xmlNewDocElementContent:
899 * @doc: the document
Owen Taylor3473f882001-02-23 17:55:21 +0000900 * @name: the subelement name or NULL
901 * @type: the type of element content decl
902 *
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000903 * Allocate an element content structure for the document.
Owen Taylor3473f882001-02-23 17:55:21 +0000904 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000905 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000906 */
907xmlElementContentPtr
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000908xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
909 xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000910 xmlElementContentPtr ret;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000911 xmlDictPtr dict = NULL;
912
913 if (doc != NULL)
914 dict = doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +0000915
916 switch(type) {
917 case XML_ELEMENT_CONTENT_ELEMENT:
918 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000919 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
920 "xmlNewElementContent : name == NULL !\n",
921 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000922 }
923 break;
924 case XML_ELEMENT_CONTENT_PCDATA:
925 case XML_ELEMENT_CONTENT_SEQ:
926 case XML_ELEMENT_CONTENT_OR:
927 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000928 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
929 "xmlNewElementContent : name != NULL !\n",
930 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000931 }
932 break;
933 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000934 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
935 "Internal: ELEMENT content corrupted invalid type\n",
936 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000937 return(NULL);
938 }
939 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
940 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000941 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000942 return(NULL);
943 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000944 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000945 ret->type = type;
946 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000947 if (name != NULL) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000948 int l;
949 const xmlChar *tmp;
950
951 tmp = xmlSplitQName3(name, &l);
952 if (tmp == NULL) {
953 if (dict == NULL)
954 ret->name = xmlStrdup(name);
955 else
956 ret->name = xmlDictLookup(dict, name, -1);
957 } else {
958 if (dict == NULL) {
959 ret->prefix = xmlStrndup(name, l);
960 ret->name = xmlStrdup(tmp);
961 } else {
962 ret->prefix = xmlDictLookup(dict, name, l);
963 ret->name = xmlDictLookup(dict, tmp, -1);
964 }
965 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000966 }
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000967 return(ret);
968}
969
970/**
971 * xmlNewElementContent:
972 * @name: the subelement name or NULL
973 * @type: the type of element content decl
974 *
975 * Allocate an element content structure.
976 * Deprecated in favor of xmlNewDocElementContent
977 *
978 * Returns NULL if not, otherwise the new element content structure
979 */
980xmlElementContentPtr
981xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
982 return(xmlNewDocElementContent(NULL, name, type));
983}
984
985/**
986 * xmlCopyDocElementContent:
987 * @doc: the document owning the element declaration
988 * @cur: An element content pointer.
989 *
990 * Build a copy of an element content description.
991 *
992 * Returns the new xmlElementContentPtr or NULL in case of error.
993 */
994xmlElementContentPtr
995xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
996 xmlElementContentPtr ret = NULL, prev = NULL, tmp;
997 xmlDictPtr dict = NULL;
998
999 if (cur == NULL) return(NULL);
1000
1001 if (doc != NULL)
1002 dict = doc->dict;
1003
1004 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1005 if (ret == NULL) {
1006 xmlVErrMemory(NULL, "malloc failed");
1007 return(NULL);
1008 }
1009 memset(ret, 0, sizeof(xmlElementContent));
1010 ret->type = cur->type;
1011 ret->ocur = cur->ocur;
1012 if (cur->name != NULL) {
1013 if (dict)
1014 ret->name = xmlDictLookup(dict, cur->name, -1);
1015 else
1016 ret->name = xmlStrdup(cur->name);
1017 }
1018
1019 if (cur->prefix != NULL) {
1020 if (dict)
1021 ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1022 else
1023 ret->prefix = xmlStrdup(cur->prefix);
1024 }
1025 if (cur->c1 != NULL)
1026 ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1027 if (ret->c1 != NULL)
1028 ret->c1->parent = ret;
1029 if (cur->c2 != NULL) {
1030 prev = ret;
1031 cur = cur->c2;
1032 while (cur != NULL) {
1033 tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1034 if (tmp == NULL) {
1035 xmlVErrMemory(NULL, "malloc failed");
1036 return(ret);
1037 }
1038 memset(tmp, 0, sizeof(xmlElementContent));
1039 tmp->type = cur->type;
1040 tmp->ocur = cur->ocur;
1041 prev->c2 = tmp;
1042 if (cur->name != NULL) {
1043 if (dict)
1044 tmp->name = xmlDictLookup(dict, cur->name, -1);
1045 else
1046 tmp->name = xmlStrdup(cur->name);
1047 }
1048
1049 if (cur->prefix != NULL) {
1050 if (dict)
1051 tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1052 else
1053 tmp->prefix = xmlStrdup(cur->prefix);
1054 }
1055 if (cur->c1 != NULL)
1056 tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1057 if (tmp->c1 != NULL)
1058 tmp->c1->parent = ret;
1059 prev = tmp;
1060 cur = cur->c2;
1061 }
1062 }
Owen Taylor3473f882001-02-23 17:55:21 +00001063 return(ret);
1064}
1065
1066/**
1067 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +00001068 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +00001069 *
1070 * Build a copy of an element content description.
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001071 * Deprecated, use xmlCopyDocElementContent instead
Owen Taylor3473f882001-02-23 17:55:21 +00001072 *
1073 * Returns the new xmlElementContentPtr or NULL in case of error.
1074 */
1075xmlElementContentPtr
1076xmlCopyElementContent(xmlElementContentPtr cur) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001077 return(xmlCopyDocElementContent(NULL, cur));
1078}
Owen Taylor3473f882001-02-23 17:55:21 +00001079
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001080/**
1081 * xmlFreeDocElementContent:
1082 * @doc: the document owning the element declaration
1083 * @cur: the element content tree to free
1084 *
1085 * Free an element content structure. The whole subtree is removed.
1086 */
1087void
1088xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1089 xmlElementContentPtr next;
1090 xmlDictPtr dict = NULL;
1091
1092 if (doc != NULL)
1093 dict = doc->dict;
1094
1095 while (cur != NULL) {
1096 next = cur->c2;
1097 switch (cur->type) {
1098 case XML_ELEMENT_CONTENT_PCDATA:
1099 case XML_ELEMENT_CONTENT_ELEMENT:
1100 case XML_ELEMENT_CONTENT_SEQ:
1101 case XML_ELEMENT_CONTENT_OR:
1102 break;
1103 default:
1104 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1105 "Internal: ELEMENT content corrupted invalid type\n",
1106 NULL);
1107 return;
1108 }
1109 if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1);
1110 if (dict) {
1111 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1112 xmlFree((xmlChar *) cur->name);
1113 if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1114 xmlFree((xmlChar *) cur->prefix);
1115 } else {
1116 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1117 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1118 }
1119 xmlFree(cur);
1120 cur = next;
Owen Taylor3473f882001-02-23 17:55:21 +00001121 }
Owen Taylor3473f882001-02-23 17:55:21 +00001122}
1123
1124/**
1125 * xmlFreeElementContent:
1126 * @cur: the element content tree to free
1127 *
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001128 * Free an element content structure. The whole subtree is removed.
1129 * Deprecated, use xmlFreeDocElementContent instead
Owen Taylor3473f882001-02-23 17:55:21 +00001130 */
1131void
1132xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001133 xmlFreeDocElementContent(NULL, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001134}
1135
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001136#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001137/**
1138 * xmlDumpElementContent:
1139 * @buf: An XML buffer
1140 * @content: An element table
1141 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1142 *
1143 * This will dump the content of the element table as an XML DTD definition
1144 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001145static void
Owen Taylor3473f882001-02-23 17:55:21 +00001146xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1147 if (content == NULL) return;
1148
1149 if (glob) xmlBufferWriteChar(buf, "(");
1150 switch (content->type) {
1151 case XML_ELEMENT_CONTENT_PCDATA:
1152 xmlBufferWriteChar(buf, "#PCDATA");
1153 break;
1154 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001155 if (content->prefix != NULL) {
1156 xmlBufferWriteCHAR(buf, content->prefix);
1157 xmlBufferWriteChar(buf, ":");
1158 }
Owen Taylor3473f882001-02-23 17:55:21 +00001159 xmlBufferWriteCHAR(buf, content->name);
1160 break;
1161 case XML_ELEMENT_CONTENT_SEQ:
1162 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1163 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1164 xmlDumpElementContent(buf, content->c1, 1);
1165 else
1166 xmlDumpElementContent(buf, content->c1, 0);
1167 xmlBufferWriteChar(buf, " , ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001168 if ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1169 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
1170 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001171 xmlDumpElementContent(buf, content->c2, 1);
1172 else
1173 xmlDumpElementContent(buf, content->c2, 0);
1174 break;
1175 case XML_ELEMENT_CONTENT_OR:
1176 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1177 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1178 xmlDumpElementContent(buf, content->c1, 1);
1179 else
1180 xmlDumpElementContent(buf, content->c1, 0);
1181 xmlBufferWriteChar(buf, " | ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001182 if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1183 ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
1184 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001185 xmlDumpElementContent(buf, content->c2, 1);
1186 else
1187 xmlDumpElementContent(buf, content->c2, 0);
1188 break;
1189 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001190 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1191 "Internal: ELEMENT content corrupted invalid type\n",
1192 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001193 }
1194 if (glob)
1195 xmlBufferWriteChar(buf, ")");
1196 switch (content->ocur) {
1197 case XML_ELEMENT_CONTENT_ONCE:
1198 break;
1199 case XML_ELEMENT_CONTENT_OPT:
1200 xmlBufferWriteChar(buf, "?");
1201 break;
1202 case XML_ELEMENT_CONTENT_MULT:
1203 xmlBufferWriteChar(buf, "*");
1204 break;
1205 case XML_ELEMENT_CONTENT_PLUS:
1206 xmlBufferWriteChar(buf, "+");
1207 break;
1208 }
1209}
1210
1211/**
1212 * xmlSprintfElementContent:
1213 * @buf: an output buffer
1214 * @content: An element table
1215 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1216 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001217 * Deprecated, unsafe, use xmlSnprintfElementContent
1218 */
1219void
1220xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1221 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1222 int glob ATTRIBUTE_UNUSED) {
1223}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001224#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001225
1226/**
1227 * xmlSnprintfElementContent:
1228 * @buf: an output buffer
1229 * @size: the buffer size
1230 * @content: An element table
1231 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1232 *
Owen Taylor3473f882001-02-23 17:55:21 +00001233 * This will dump the content of the element content definition
1234 * Intended just for the debug routine
1235 */
1236void
Daniel Veillardd3d06722001-08-15 12:06:36 +00001237xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int glob) {
1238 int len;
1239
Owen Taylor3473f882001-02-23 17:55:21 +00001240 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001241 len = strlen(buf);
1242 if (size - len < 50) {
1243 if ((size - len > 4) && (buf[len - 1] != '.'))
1244 strcat(buf, " ...");
1245 return;
1246 }
Owen Taylor3473f882001-02-23 17:55:21 +00001247 if (glob) strcat(buf, "(");
1248 switch (content->type) {
1249 case XML_ELEMENT_CONTENT_PCDATA:
1250 strcat(buf, "#PCDATA");
1251 break;
1252 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001253 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001254 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001255 strcat(buf, " ...");
1256 return;
1257 }
1258 strcat(buf, (char *) content->prefix);
1259 strcat(buf, ":");
1260 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001261 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001262 strcat(buf, " ...");
1263 return;
1264 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001265 if (content->name != NULL)
1266 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001267 break;
1268 case XML_ELEMENT_CONTENT_SEQ:
1269 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1270 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001271 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001272 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001273 xmlSnprintfElementContent(buf, size, content->c1, 0);
1274 len = strlen(buf);
1275 if (size - len < 50) {
1276 if ((size - len > 4) && (buf[len - 1] != '.'))
1277 strcat(buf, " ...");
1278 return;
1279 }
Owen Taylor3473f882001-02-23 17:55:21 +00001280 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001281 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1282 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1283 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001284 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001285 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001286 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001287 break;
1288 case XML_ELEMENT_CONTENT_OR:
1289 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1290 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001291 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001292 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001293 xmlSnprintfElementContent(buf, size, content->c1, 0);
1294 len = strlen(buf);
1295 if (size - len < 50) {
1296 if ((size - len > 4) && (buf[len - 1] != '.'))
1297 strcat(buf, " ...");
1298 return;
1299 }
Owen Taylor3473f882001-02-23 17:55:21 +00001300 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001301 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1302 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1303 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001304 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001305 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001306 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001307 break;
1308 }
1309 if (glob)
1310 strcat(buf, ")");
1311 switch (content->ocur) {
1312 case XML_ELEMENT_CONTENT_ONCE:
1313 break;
1314 case XML_ELEMENT_CONTENT_OPT:
1315 strcat(buf, "?");
1316 break;
1317 case XML_ELEMENT_CONTENT_MULT:
1318 strcat(buf, "*");
1319 break;
1320 case XML_ELEMENT_CONTENT_PLUS:
1321 strcat(buf, "+");
1322 break;
1323 }
1324}
1325
1326/****************************************************************
1327 * *
1328 * Registration of DTD declarations *
1329 * *
1330 ****************************************************************/
1331
1332/**
Owen Taylor3473f882001-02-23 17:55:21 +00001333 * xmlFreeElement:
1334 * @elem: An element
1335 *
1336 * Deallocate the memory used by an element definition
1337 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001338static void
Owen Taylor3473f882001-02-23 17:55:21 +00001339xmlFreeElement(xmlElementPtr elem) {
1340 if (elem == NULL) return;
1341 xmlUnlinkNode((xmlNodePtr) elem);
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001342 xmlFreeDocElementContent(elem->doc, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001343 if (elem->name != NULL)
1344 xmlFree((xmlChar *) elem->name);
1345 if (elem->prefix != NULL)
1346 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001347#ifdef LIBXML_REGEXP_ENABLED
1348 if (elem->contModel != NULL)
1349 xmlRegFreeRegexp(elem->contModel);
1350#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001351 xmlFree(elem);
1352}
1353
1354
1355/**
1356 * xmlAddElementDecl:
1357 * @ctxt: the validation context
1358 * @dtd: pointer to the DTD
1359 * @name: the entity name
1360 * @type: the element type
1361 * @content: the element content tree or NULL
1362 *
1363 * Register a new element declaration
1364 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001365 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001366 */
1367xmlElementPtr
William M. Brackedb65a72004-02-06 07:36:04 +00001368xmlAddElementDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001369 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001370 xmlElementTypeVal type,
1371 xmlElementContentPtr content) {
1372 xmlElementPtr ret;
1373 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001374 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001375 xmlChar *ns, *uqname;
1376
1377 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001378 return(NULL);
1379 }
1380 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001381 return(NULL);
1382 }
Daniel Veillard316a5c32005-01-23 22:56:39 +00001383
Owen Taylor3473f882001-02-23 17:55:21 +00001384 switch (type) {
1385 case XML_ELEMENT_TYPE_EMPTY:
1386 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001387 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1388 "xmlAddElementDecl: content != NULL for EMPTY\n",
1389 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001390 return(NULL);
1391 }
1392 break;
1393 case XML_ELEMENT_TYPE_ANY:
1394 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001395 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1396 "xmlAddElementDecl: content != NULL for ANY\n",
1397 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001398 return(NULL);
1399 }
1400 break;
1401 case XML_ELEMENT_TYPE_MIXED:
1402 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001403 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1404 "xmlAddElementDecl: content == NULL for MIXED\n",
1405 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001406 return(NULL);
1407 }
1408 break;
1409 case XML_ELEMENT_TYPE_ELEMENT:
1410 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001411 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1412 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1413 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001414 return(NULL);
1415 }
1416 break;
1417 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001418 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1419 "Internal: ELEMENT decl corrupted invalid type\n",
1420 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001421 return(NULL);
1422 }
1423
1424 /*
1425 * check if name is a QName
1426 */
1427 uqname = xmlSplitQName2(name, &ns);
1428 if (uqname != NULL)
1429 name = uqname;
1430
1431 /*
1432 * Create the Element table if needed.
1433 */
1434 table = (xmlElementTablePtr) dtd->elements;
1435 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00001436 xmlDictPtr dict = NULL;
1437
1438 if (dtd->doc != NULL)
1439 dict = dtd->doc->dict;
1440 table = xmlHashCreateDict(0, dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001441 dtd->elements = (void *) table;
1442 }
1443 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001444 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001445 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001446 if (uqname != NULL)
1447 xmlFree(uqname);
1448 if (ns != NULL)
1449 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001450 return(NULL);
1451 }
1452
Daniel Veillarda10efa82001-04-18 13:09:01 +00001453 /*
1454 * lookup old attributes inserted on an undefined element in the
1455 * internal subset.
1456 */
1457 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1458 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1459 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1460 oldAttributes = ret->attributes;
1461 ret->attributes = NULL;
1462 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1463 xmlFreeElement(ret);
1464 }
Owen Taylor3473f882001-02-23 17:55:21 +00001465 }
Owen Taylor3473f882001-02-23 17:55:21 +00001466
1467 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001468 * The element may already be present if one of its attribute
1469 * was registered first
1470 */
1471 ret = xmlHashLookup2(table, name, ns);
1472 if (ret != NULL) {
1473 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001474#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001475 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001476 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001477 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001478 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1479 "Redefinition of element %s\n",
1480 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001481#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001482 if (uqname != NULL)
1483 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001484 if (ns != NULL)
1485 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001486 return(NULL);
1487 }
1488 } else {
1489 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1490 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001491 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001492 if (uqname != NULL)
1493 xmlFree(uqname);
1494 if (ns != NULL)
1495 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001496 return(NULL);
1497 }
1498 memset(ret, 0, sizeof(xmlElement));
1499 ret->type = XML_ELEMENT_DECL;
1500
1501 /*
1502 * fill the structure.
1503 */
1504 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001505 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001506 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001507 if (uqname != NULL)
1508 xmlFree(uqname);
1509 if (ns != NULL)
1510 xmlFree(ns);
1511 xmlFree(ret);
1512 return(NULL);
1513 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001514 ret->prefix = ns;
1515
1516 /*
1517 * Validity Check:
1518 * Insertion must not fail
1519 */
1520 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001521#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001522 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001523 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001524 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001525 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1526 "Redefinition of element %s\n",
1527 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001528#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001529 xmlFreeElement(ret);
1530 if (uqname != NULL)
1531 xmlFree(uqname);
1532 return(NULL);
1533 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001534 /*
1535 * For new element, may have attributes from earlier
1536 * definition in internal subset
1537 */
1538 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001539 }
1540
1541 /*
1542 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001543 */
1544 ret->etype = type;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001545 /*
1546 * Avoid a stupid copy when called by the parser
1547 * and flag it by setting a special parent value
1548 * so the parser doesn't unallocate it.
1549 */
Daniel Veillardc394f732005-01-26 00:04:52 +00001550 if ((ctxt != NULL) &&
1551 ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
1552 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001553 ret->content = content;
1554 if (content != NULL)
1555 content->parent = (xmlElementContentPtr) 1;
1556 } else {
1557 ret->content = xmlCopyDocElementContent(dtd->doc, content);
1558 }
Owen Taylor3473f882001-02-23 17:55:21 +00001559
1560 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001561 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001562 */
1563 ret->parent = dtd;
1564 ret->doc = dtd->doc;
1565 if (dtd->last == NULL) {
1566 dtd->children = dtd->last = (xmlNodePtr) ret;
1567 } else {
1568 dtd->last->next = (xmlNodePtr) ret;
1569 ret->prev = dtd->last;
1570 dtd->last = (xmlNodePtr) ret;
1571 }
1572 if (uqname != NULL)
1573 xmlFree(uqname);
1574 return(ret);
1575}
1576
1577/**
1578 * xmlFreeElementTable:
1579 * @table: An element table
1580 *
1581 * Deallocate the memory used by an element hash table.
1582 */
1583void
1584xmlFreeElementTable(xmlElementTablePtr table) {
1585 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1586}
1587
Daniel Veillard652327a2003-09-29 18:02:38 +00001588#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001589/**
1590 * xmlCopyElement:
1591 * @elem: An element
1592 *
1593 * Build a copy of an element.
1594 *
1595 * Returns the new xmlElementPtr or NULL in case of error.
1596 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001597static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001598xmlCopyElement(xmlElementPtr elem) {
1599 xmlElementPtr cur;
1600
1601 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1602 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001603 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001604 return(NULL);
1605 }
1606 memset(cur, 0, sizeof(xmlElement));
1607 cur->type = XML_ELEMENT_DECL;
1608 cur->etype = elem->etype;
1609 if (elem->name != NULL)
1610 cur->name = xmlStrdup(elem->name);
1611 else
1612 cur->name = NULL;
1613 if (elem->prefix != NULL)
1614 cur->prefix = xmlStrdup(elem->prefix);
1615 else
1616 cur->prefix = NULL;
1617 cur->content = xmlCopyElementContent(elem->content);
1618 /* TODO : rebuild the attribute list on the copy */
1619 cur->attributes = NULL;
1620 return(cur);
1621}
1622
1623/**
1624 * xmlCopyElementTable:
1625 * @table: An element table
1626 *
1627 * Build a copy of an element table.
1628 *
1629 * Returns the new xmlElementTablePtr or NULL in case of error.
1630 */
1631xmlElementTablePtr
1632xmlCopyElementTable(xmlElementTablePtr table) {
1633 return((xmlElementTablePtr) xmlHashCopy(table,
1634 (xmlHashCopier) xmlCopyElement));
1635}
Daniel Veillard652327a2003-09-29 18:02:38 +00001636#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001637
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001638#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001639/**
1640 * xmlDumpElementDecl:
1641 * @buf: the XML buffer output
1642 * @elem: An element table
1643 *
1644 * This will dump the content of the element declaration as an XML
1645 * DTD definition
1646 */
1647void
1648xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001649 if ((buf == NULL) || (elem == NULL))
1650 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001651 switch (elem->etype) {
1652 case XML_ELEMENT_TYPE_EMPTY:
1653 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001654 if (elem->prefix != NULL) {
1655 xmlBufferWriteCHAR(buf, elem->prefix);
1656 xmlBufferWriteChar(buf, ":");
1657 }
Owen Taylor3473f882001-02-23 17:55:21 +00001658 xmlBufferWriteCHAR(buf, elem->name);
1659 xmlBufferWriteChar(buf, " EMPTY>\n");
1660 break;
1661 case XML_ELEMENT_TYPE_ANY:
1662 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001663 if (elem->prefix != NULL) {
1664 xmlBufferWriteCHAR(buf, elem->prefix);
1665 xmlBufferWriteChar(buf, ":");
1666 }
Owen Taylor3473f882001-02-23 17:55:21 +00001667 xmlBufferWriteCHAR(buf, elem->name);
1668 xmlBufferWriteChar(buf, " ANY>\n");
1669 break;
1670 case XML_ELEMENT_TYPE_MIXED:
1671 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001672 if (elem->prefix != NULL) {
1673 xmlBufferWriteCHAR(buf, elem->prefix);
1674 xmlBufferWriteChar(buf, ":");
1675 }
Owen Taylor3473f882001-02-23 17:55:21 +00001676 xmlBufferWriteCHAR(buf, elem->name);
1677 xmlBufferWriteChar(buf, " ");
1678 xmlDumpElementContent(buf, elem->content, 1);
1679 xmlBufferWriteChar(buf, ">\n");
1680 break;
1681 case XML_ELEMENT_TYPE_ELEMENT:
1682 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001683 if (elem->prefix != NULL) {
1684 xmlBufferWriteCHAR(buf, elem->prefix);
1685 xmlBufferWriteChar(buf, ":");
1686 }
Owen Taylor3473f882001-02-23 17:55:21 +00001687 xmlBufferWriteCHAR(buf, elem->name);
1688 xmlBufferWriteChar(buf, " ");
1689 xmlDumpElementContent(buf, elem->content, 1);
1690 xmlBufferWriteChar(buf, ">\n");
1691 break;
1692 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001693 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1694 "Internal: ELEMENT struct corrupted invalid type\n",
1695 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001696 }
1697}
1698
1699/**
William M. Brack9e660592003-10-20 14:56:06 +00001700 * xmlDumpElementDeclScan:
1701 * @elem: An element table
1702 * @buf: the XML buffer output
1703 *
1704 * This routine is used by the hash scan function. It just reverses
1705 * the arguments.
1706 */
1707static void
1708xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1709 xmlDumpElementDecl(buf, elem);
1710}
1711
1712/**
Owen Taylor3473f882001-02-23 17:55:21 +00001713 * xmlDumpElementTable:
1714 * @buf: the XML buffer output
1715 * @table: An element table
1716 *
1717 * This will dump the content of the element table as an XML DTD definition
1718 */
1719void
1720xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001721 if ((buf == NULL) || (table == NULL))
1722 return;
William M. Brack9e660592003-10-20 14:56:06 +00001723 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001724}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001725#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001726
1727/**
1728 * xmlCreateEnumeration:
1729 * @name: the enumeration name or NULL
1730 *
1731 * create and initialize an enumeration attribute node.
1732 *
1733 * Returns the xmlEnumerationPtr just created or NULL in case
1734 * of error.
1735 */
1736xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001737xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001738 xmlEnumerationPtr ret;
1739
1740 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1741 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001742 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001743 return(NULL);
1744 }
1745 memset(ret, 0, sizeof(xmlEnumeration));
1746
1747 if (name != NULL)
1748 ret->name = xmlStrdup(name);
1749 return(ret);
1750}
1751
1752/**
1753 * xmlFreeEnumeration:
1754 * @cur: the tree to free.
1755 *
1756 * free an enumeration attribute node (recursive).
1757 */
1758void
1759xmlFreeEnumeration(xmlEnumerationPtr cur) {
1760 if (cur == NULL) return;
1761
1762 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1763
1764 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001765 xmlFree(cur);
1766}
1767
Daniel Veillard652327a2003-09-29 18:02:38 +00001768#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001769/**
1770 * xmlCopyEnumeration:
1771 * @cur: the tree to copy.
1772 *
1773 * Copy an enumeration attribute node (recursive).
1774 *
1775 * Returns the xmlEnumerationPtr just created or NULL in case
1776 * of error.
1777 */
1778xmlEnumerationPtr
1779xmlCopyEnumeration(xmlEnumerationPtr cur) {
1780 xmlEnumerationPtr ret;
1781
1782 if (cur == NULL) return(NULL);
1783 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1784
1785 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1786 else ret->next = NULL;
1787
1788 return(ret);
1789}
Daniel Veillard652327a2003-09-29 18:02:38 +00001790#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001791
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001792#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001793/**
1794 * xmlDumpEnumeration:
1795 * @buf: the XML buffer output
1796 * @enum: An enumeration
1797 *
1798 * This will dump the content of the enumeration
1799 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001800static void
Owen Taylor3473f882001-02-23 17:55:21 +00001801xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001802 if ((buf == NULL) || (cur == NULL))
1803 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001804
1805 xmlBufferWriteCHAR(buf, cur->name);
1806 if (cur->next == NULL)
1807 xmlBufferWriteChar(buf, ")");
1808 else {
1809 xmlBufferWriteChar(buf, " | ");
1810 xmlDumpEnumeration(buf, cur->next);
1811 }
1812}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001813#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001814
Daniel Veillard4432df22003-09-28 18:58:27 +00001815#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001816/**
1817 * xmlScanAttributeDeclCallback:
1818 * @attr: the attribute decl
1819 * @list: the list to update
1820 *
1821 * Callback called by xmlScanAttributeDecl when a new attribute
1822 * has to be entered in the list.
1823 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001824static void
Owen Taylor3473f882001-02-23 17:55:21 +00001825xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001826 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001827 attr->nexth = *list;
1828 *list = attr;
1829}
1830
1831/**
1832 * xmlScanAttributeDecl:
1833 * @dtd: pointer to the DTD
1834 * @elem: the element name
1835 *
1836 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001837 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001838 *
1839 * Returns the pointer to the first attribute decl in the chain,
1840 * possibly NULL.
1841 */
1842xmlAttributePtr
1843xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1844 xmlAttributePtr ret = NULL;
1845 xmlAttributeTablePtr table;
1846
1847 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001848 return(NULL);
1849 }
1850 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001851 return(NULL);
1852 }
1853 table = (xmlAttributeTablePtr) dtd->attributes;
1854 if (table == NULL)
1855 return(NULL);
1856
1857 /* WRONG !!! */
1858 xmlHashScan3(table, NULL, NULL, elem,
1859 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1860 return(ret);
1861}
1862
1863/**
1864 * xmlScanIDAttributeDecl:
1865 * @ctxt: the validation context
1866 * @elem: the element name
1867 *
1868 * Verify that the element don't have too many ID attributes
1869 * declared.
1870 *
1871 * Returns the number of ID attributes found.
1872 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001873static int
Owen Taylor3473f882001-02-23 17:55:21 +00001874xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1875 xmlAttributePtr cur;
1876 int ret = 0;
1877
1878 if (elem == NULL) return(0);
1879 cur = elem->attributes;
1880 while (cur != NULL) {
1881 if (cur->atype == XML_ATTRIBUTE_ID) {
1882 ret ++;
1883 if (ret > 1)
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001884 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001885 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001886 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001887 }
1888 cur = cur->nexth;
1889 }
1890 return(ret);
1891}
Daniel Veillard4432df22003-09-28 18:58:27 +00001892#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001893
1894/**
1895 * xmlFreeAttribute:
1896 * @elem: An attribute
1897 *
1898 * Deallocate the memory used by an attribute definition
1899 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001900static void
Owen Taylor3473f882001-02-23 17:55:21 +00001901xmlFreeAttribute(xmlAttributePtr attr) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001902 xmlDictPtr dict;
1903
Owen Taylor3473f882001-02-23 17:55:21 +00001904 if (attr == NULL) return;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001905 if (attr->doc != NULL)
1906 dict = attr->doc->dict;
1907 else
1908 dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001909 xmlUnlinkNode((xmlNodePtr) attr);
1910 if (attr->tree != NULL)
1911 xmlFreeEnumeration(attr->tree);
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001912 if (dict) {
1913 if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1914 xmlFree((xmlChar *) attr->elem);
1915 if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1916 xmlFree((xmlChar *) attr->name);
1917 if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1918 xmlFree((xmlChar *) attr->prefix);
1919 if ((attr->defaultValue != NULL) &&
1920 (!xmlDictOwns(dict, attr->defaultValue)))
1921 xmlFree((xmlChar *) attr->defaultValue);
1922 } else {
1923 if (attr->elem != NULL)
1924 xmlFree((xmlChar *) attr->elem);
1925 if (attr->name != NULL)
1926 xmlFree((xmlChar *) attr->name);
1927 if (attr->defaultValue != NULL)
1928 xmlFree((xmlChar *) attr->defaultValue);
1929 if (attr->prefix != NULL)
1930 xmlFree((xmlChar *) attr->prefix);
1931 }
Owen Taylor3473f882001-02-23 17:55:21 +00001932 xmlFree(attr);
1933}
1934
1935
1936/**
1937 * xmlAddAttributeDecl:
1938 * @ctxt: the validation context
1939 * @dtd: pointer to the DTD
1940 * @elem: the element name
1941 * @name: the attribute name
1942 * @ns: the attribute namespace prefix
1943 * @type: the attribute type
1944 * @def: the attribute default type
1945 * @defaultValue: the attribute default value
1946 * @tree: if it's an enumeration, the associated list
1947 *
1948 * Register a new attribute declaration
1949 * Note that @tree becomes the ownership of the DTD
1950 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001951 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001952 */
1953xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001954xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001955 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001956 const xmlChar *name, const xmlChar *ns,
1957 xmlAttributeType type, xmlAttributeDefault def,
1958 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1959 xmlAttributePtr ret;
1960 xmlAttributeTablePtr table;
1961 xmlElementPtr elemDef;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001962 xmlDictPtr dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001963
1964 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001965 xmlFreeEnumeration(tree);
1966 return(NULL);
1967 }
1968 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001969 xmlFreeEnumeration(tree);
1970 return(NULL);
1971 }
1972 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001973 xmlFreeEnumeration(tree);
1974 return(NULL);
1975 }
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001976 if (dtd->doc != NULL)
1977 dict = dtd->doc->dict;
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001978
Daniel Veillard4432df22003-09-28 18:58:27 +00001979#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001980 /*
1981 * Check the type and possibly the default value.
1982 */
1983 switch (type) {
1984 case XML_ATTRIBUTE_CDATA:
1985 break;
1986 case XML_ATTRIBUTE_ID:
1987 break;
1988 case XML_ATTRIBUTE_IDREF:
1989 break;
1990 case XML_ATTRIBUTE_IDREFS:
1991 break;
1992 case XML_ATTRIBUTE_ENTITY:
1993 break;
1994 case XML_ATTRIBUTE_ENTITIES:
1995 break;
1996 case XML_ATTRIBUTE_NMTOKEN:
1997 break;
1998 case XML_ATTRIBUTE_NMTOKENS:
1999 break;
2000 case XML_ATTRIBUTE_ENUMERATION:
2001 break;
2002 case XML_ATTRIBUTE_NOTATION:
2003 break;
2004 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002005 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
2006 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2007 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002008 xmlFreeEnumeration(tree);
2009 return(NULL);
2010 }
2011 if ((defaultValue != NULL) &&
2012 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002013 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
2014 "Attribute %s of %s: invalid default value\n",
2015 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00002016 defaultValue = NULL;
Daniel Veillard42595322004-11-08 10:52:06 +00002017 if (ctxt != NULL)
2018 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002019 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002020#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002021
2022 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00002023 * Check first that an attribute defined in the external subset wasn't
2024 * already defined in the internal subset
2025 */
2026 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2027 (dtd->doc->intSubset != NULL) &&
2028 (dtd->doc->intSubset->attributes != NULL)) {
2029 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2030 if (ret != NULL)
2031 return(NULL);
2032 }
2033
2034 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002035 * Create the Attribute table if needed.
2036 */
2037 table = (xmlAttributeTablePtr) dtd->attributes;
2038 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00002039 table = xmlHashCreateDict(0, dict);
Owen Taylor3473f882001-02-23 17:55:21 +00002040 dtd->attributes = (void *) table;
2041 }
2042 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002043 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002044 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002045 return(NULL);
2046 }
2047
2048
2049 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2050 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002051 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002052 return(NULL);
2053 }
2054 memset(ret, 0, sizeof(xmlAttribute));
2055 ret->type = XML_ATTRIBUTE_DECL;
2056
2057 /*
2058 * fill the structure.
2059 */
2060 ret->atype = type;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002061 if (dict) {
2062 ret->name = xmlDictLookup(dict, name, -1);
2063 ret->prefix = xmlDictLookup(dict, ns, -1);
2064 ret->elem = xmlDictLookup(dict, elem, -1);
2065 } else {
2066 ret->name = xmlStrdup(name);
2067 ret->prefix = xmlStrdup(ns);
2068 ret->elem = xmlStrdup(elem);
2069 }
Owen Taylor3473f882001-02-23 17:55:21 +00002070 ret->def = def;
2071 ret->tree = tree;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002072 if (defaultValue != NULL) {
2073 if (dict)
2074 ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2075 else
2076 ret->defaultValue = xmlStrdup(defaultValue);
2077 }
Owen Taylor3473f882001-02-23 17:55:21 +00002078
2079 /*
2080 * Validity Check:
2081 * Search the DTD for previous declarations of the ATTLIST
2082 */
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002083 if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002084#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002085 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002086 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002087 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002088 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00002089 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002090 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00002091#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002092 xmlFreeAttribute(ret);
2093 return(NULL);
2094 }
2095
2096 /*
2097 * Validity Check:
2098 * Multiple ID per element
2099 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00002100 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002101 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00002102
Daniel Veillard4432df22003-09-28 18:58:27 +00002103#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002104 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00002105 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002106 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00002107 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002108 elem, name, NULL);
Daniel Veillard42595322004-11-08 10:52:06 +00002109 if (ctxt != NULL)
2110 ctxt->valid = 0;
Daniel Veillardc7612992002-02-17 22:47:37 +00002111 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002112#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00002113
Daniel Veillard48da9102001-08-07 01:10:10 +00002114 /*
2115 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002116 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00002117 */
2118 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2119 ((ret->prefix != NULL &&
2120 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2121 ret->nexth = elemDef->attributes;
2122 elemDef->attributes = ret;
2123 } else {
2124 xmlAttributePtr tmp = elemDef->attributes;
2125
2126 while ((tmp != NULL) &&
2127 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2128 ((ret->prefix != NULL &&
2129 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2130 if (tmp->nexth == NULL)
2131 break;
2132 tmp = tmp->nexth;
2133 }
2134 if (tmp != NULL) {
2135 ret->nexth = tmp->nexth;
2136 tmp->nexth = ret;
2137 } else {
2138 ret->nexth = elemDef->attributes;
2139 elemDef->attributes = ret;
2140 }
2141 }
Owen Taylor3473f882001-02-23 17:55:21 +00002142 }
2143
2144 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002145 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00002146 */
2147 ret->parent = dtd;
2148 ret->doc = dtd->doc;
2149 if (dtd->last == NULL) {
2150 dtd->children = dtd->last = (xmlNodePtr) ret;
2151 } else {
2152 dtd->last->next = (xmlNodePtr) ret;
2153 ret->prev = dtd->last;
2154 dtd->last = (xmlNodePtr) ret;
2155 }
2156 return(ret);
2157}
2158
2159/**
2160 * xmlFreeAttributeTable:
2161 * @table: An attribute table
2162 *
2163 * Deallocate the memory used by an entities hash table.
2164 */
2165void
2166xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2167 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
2168}
2169
Daniel Veillard652327a2003-09-29 18:02:38 +00002170#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002171/**
2172 * xmlCopyAttribute:
2173 * @attr: An attribute
2174 *
2175 * Build a copy of an attribute.
2176 *
2177 * Returns the new xmlAttributePtr or NULL in case of error.
2178 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002179static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002180xmlCopyAttribute(xmlAttributePtr attr) {
2181 xmlAttributePtr cur;
2182
2183 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2184 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002185 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002186 return(NULL);
2187 }
2188 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00002189 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00002190 cur->atype = attr->atype;
2191 cur->def = attr->def;
2192 cur->tree = xmlCopyEnumeration(attr->tree);
2193 if (attr->elem != NULL)
2194 cur->elem = xmlStrdup(attr->elem);
2195 if (attr->name != NULL)
2196 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002197 if (attr->prefix != NULL)
2198 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002199 if (attr->defaultValue != NULL)
2200 cur->defaultValue = xmlStrdup(attr->defaultValue);
2201 return(cur);
2202}
2203
2204/**
2205 * xmlCopyAttributeTable:
2206 * @table: An attribute table
2207 *
2208 * Build a copy of an attribute table.
2209 *
2210 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2211 */
2212xmlAttributeTablePtr
2213xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2214 return((xmlAttributeTablePtr) xmlHashCopy(table,
2215 (xmlHashCopier) xmlCopyAttribute));
2216}
Daniel Veillard652327a2003-09-29 18:02:38 +00002217#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002218
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002219#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002220/**
2221 * xmlDumpAttributeDecl:
2222 * @buf: the XML buffer output
2223 * @attr: An attribute declaration
2224 *
2225 * This will dump the content of the attribute declaration as an XML
2226 * DTD definition
2227 */
2228void
2229xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002230 if ((buf == NULL) || (attr == NULL))
2231 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002232 xmlBufferWriteChar(buf, "<!ATTLIST ");
2233 xmlBufferWriteCHAR(buf, attr->elem);
2234 xmlBufferWriteChar(buf, " ");
2235 if (attr->prefix != NULL) {
2236 xmlBufferWriteCHAR(buf, attr->prefix);
2237 xmlBufferWriteChar(buf, ":");
2238 }
2239 xmlBufferWriteCHAR(buf, attr->name);
2240 switch (attr->atype) {
2241 case XML_ATTRIBUTE_CDATA:
2242 xmlBufferWriteChar(buf, " CDATA");
2243 break;
2244 case XML_ATTRIBUTE_ID:
2245 xmlBufferWriteChar(buf, " ID");
2246 break;
2247 case XML_ATTRIBUTE_IDREF:
2248 xmlBufferWriteChar(buf, " IDREF");
2249 break;
2250 case XML_ATTRIBUTE_IDREFS:
2251 xmlBufferWriteChar(buf, " IDREFS");
2252 break;
2253 case XML_ATTRIBUTE_ENTITY:
2254 xmlBufferWriteChar(buf, " ENTITY");
2255 break;
2256 case XML_ATTRIBUTE_ENTITIES:
2257 xmlBufferWriteChar(buf, " ENTITIES");
2258 break;
2259 case XML_ATTRIBUTE_NMTOKEN:
2260 xmlBufferWriteChar(buf, " NMTOKEN");
2261 break;
2262 case XML_ATTRIBUTE_NMTOKENS:
2263 xmlBufferWriteChar(buf, " NMTOKENS");
2264 break;
2265 case XML_ATTRIBUTE_ENUMERATION:
2266 xmlBufferWriteChar(buf, " (");
2267 xmlDumpEnumeration(buf, attr->tree);
2268 break;
2269 case XML_ATTRIBUTE_NOTATION:
2270 xmlBufferWriteChar(buf, " NOTATION (");
2271 xmlDumpEnumeration(buf, attr->tree);
2272 break;
2273 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002274 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2275 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2276 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002277 }
2278 switch (attr->def) {
2279 case XML_ATTRIBUTE_NONE:
2280 break;
2281 case XML_ATTRIBUTE_REQUIRED:
2282 xmlBufferWriteChar(buf, " #REQUIRED");
2283 break;
2284 case XML_ATTRIBUTE_IMPLIED:
2285 xmlBufferWriteChar(buf, " #IMPLIED");
2286 break;
2287 case XML_ATTRIBUTE_FIXED:
2288 xmlBufferWriteChar(buf, " #FIXED");
2289 break;
2290 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002291 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2292 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2293 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002294 }
2295 if (attr->defaultValue != NULL) {
2296 xmlBufferWriteChar(buf, " ");
2297 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2298 }
2299 xmlBufferWriteChar(buf, ">\n");
2300}
2301
2302/**
William M. Brack9e660592003-10-20 14:56:06 +00002303 * xmlDumpAttributeDeclScan:
2304 * @attr: An attribute declaration
2305 * @buf: the XML buffer output
2306 *
2307 * This is used with the hash scan function - just reverses arguments
2308 */
2309static void
2310xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2311 xmlDumpAttributeDecl(buf, attr);
2312}
2313
2314/**
Owen Taylor3473f882001-02-23 17:55:21 +00002315 * xmlDumpAttributeTable:
2316 * @buf: the XML buffer output
2317 * @table: An attribute table
2318 *
2319 * This will dump the content of the attribute table as an XML DTD definition
2320 */
2321void
2322xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002323 if ((buf == NULL) || (table == NULL))
2324 return;
William M. Brack9e660592003-10-20 14:56:06 +00002325 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002326}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002327#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002328
2329/************************************************************************
2330 * *
2331 * NOTATIONs *
2332 * *
2333 ************************************************************************/
2334/**
Owen Taylor3473f882001-02-23 17:55:21 +00002335 * xmlFreeNotation:
2336 * @not: A notation
2337 *
2338 * Deallocate the memory used by an notation definition
2339 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002340static void
Owen Taylor3473f882001-02-23 17:55:21 +00002341xmlFreeNotation(xmlNotationPtr nota) {
2342 if (nota == NULL) return;
2343 if (nota->name != NULL)
2344 xmlFree((xmlChar *) nota->name);
2345 if (nota->PublicID != NULL)
2346 xmlFree((xmlChar *) nota->PublicID);
2347 if (nota->SystemID != NULL)
2348 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002349 xmlFree(nota);
2350}
2351
2352
2353/**
2354 * xmlAddNotationDecl:
2355 * @dtd: pointer to the DTD
2356 * @ctxt: the validation context
2357 * @name: the entity name
2358 * @PublicID: the public identifier or NULL
2359 * @SystemID: the system identifier or NULL
2360 *
2361 * Register a new notation declaration
2362 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002363 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002364 */
2365xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002366xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002367 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002368 const xmlChar *PublicID, const xmlChar *SystemID) {
2369 xmlNotationPtr ret;
2370 xmlNotationTablePtr table;
2371
2372 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002373 return(NULL);
2374 }
2375 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002376 return(NULL);
2377 }
2378 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002379 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002380 }
2381
2382 /*
2383 * Create the Notation table if needed.
2384 */
2385 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002386 if (table == NULL) {
2387 xmlDictPtr dict = NULL;
2388 if (dtd->doc != NULL)
2389 dict = dtd->doc->dict;
2390
2391 dtd->notations = table = xmlHashCreateDict(0, dict);
2392 }
Owen Taylor3473f882001-02-23 17:55:21 +00002393 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002394 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002395 "xmlAddNotationDecl: Table creation failed!\n");
2396 return(NULL);
2397 }
2398
2399 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2400 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002401 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002402 return(NULL);
2403 }
2404 memset(ret, 0, sizeof(xmlNotation));
2405
2406 /*
2407 * fill the structure.
2408 */
2409 ret->name = xmlStrdup(name);
2410 if (SystemID != NULL)
2411 ret->SystemID = xmlStrdup(SystemID);
2412 if (PublicID != NULL)
2413 ret->PublicID = xmlStrdup(PublicID);
2414
2415 /*
2416 * Validity Check:
2417 * Check the DTD for previous declarations of the ATTLIST
2418 */
2419 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002420#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002421 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2422 "xmlAddNotationDecl: %s already defined\n",
2423 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002424#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002425 xmlFreeNotation(ret);
2426 return(NULL);
2427 }
2428 return(ret);
2429}
2430
2431/**
2432 * xmlFreeNotationTable:
2433 * @table: An notation table
2434 *
2435 * Deallocate the memory used by an entities hash table.
2436 */
2437void
2438xmlFreeNotationTable(xmlNotationTablePtr table) {
2439 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2440}
2441
Daniel Veillard652327a2003-09-29 18:02:38 +00002442#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002443/**
2444 * xmlCopyNotation:
2445 * @nota: A notation
2446 *
2447 * Build a copy of a notation.
2448 *
2449 * Returns the new xmlNotationPtr or NULL in case of error.
2450 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002451static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002452xmlCopyNotation(xmlNotationPtr nota) {
2453 xmlNotationPtr cur;
2454
2455 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2456 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002457 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002458 return(NULL);
2459 }
2460 if (nota->name != NULL)
2461 cur->name = xmlStrdup(nota->name);
2462 else
2463 cur->name = NULL;
2464 if (nota->PublicID != NULL)
2465 cur->PublicID = xmlStrdup(nota->PublicID);
2466 else
2467 cur->PublicID = NULL;
2468 if (nota->SystemID != NULL)
2469 cur->SystemID = xmlStrdup(nota->SystemID);
2470 else
2471 cur->SystemID = NULL;
2472 return(cur);
2473}
2474
2475/**
2476 * xmlCopyNotationTable:
2477 * @table: A notation table
2478 *
2479 * Build a copy of a notation table.
2480 *
2481 * Returns the new xmlNotationTablePtr or NULL in case of error.
2482 */
2483xmlNotationTablePtr
2484xmlCopyNotationTable(xmlNotationTablePtr table) {
2485 return((xmlNotationTablePtr) xmlHashCopy(table,
2486 (xmlHashCopier) xmlCopyNotation));
2487}
Daniel Veillard652327a2003-09-29 18:02:38 +00002488#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002489
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002490#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002491/**
2492 * xmlDumpNotationDecl:
2493 * @buf: the XML buffer output
2494 * @nota: A notation declaration
2495 *
2496 * This will dump the content the notation declaration as an XML DTD definition
2497 */
2498void
2499xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002500 if ((buf == NULL) || (nota == NULL))
2501 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002502 xmlBufferWriteChar(buf, "<!NOTATION ");
2503 xmlBufferWriteCHAR(buf, nota->name);
2504 if (nota->PublicID != NULL) {
2505 xmlBufferWriteChar(buf, " PUBLIC ");
2506 xmlBufferWriteQuotedString(buf, nota->PublicID);
2507 if (nota->SystemID != NULL) {
2508 xmlBufferWriteChar(buf, " ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002509 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002510 }
2511 } else {
2512 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002513 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002514 }
2515 xmlBufferWriteChar(buf, " >\n");
2516}
2517
2518/**
William M. Brack9e660592003-10-20 14:56:06 +00002519 * xmlDumpNotationDeclScan:
2520 * @nota: A notation declaration
2521 * @buf: the XML buffer output
2522 *
2523 * This is called with the hash scan function, and just reverses args
2524 */
2525static void
2526xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2527 xmlDumpNotationDecl(buf, nota);
2528}
2529
2530/**
Owen Taylor3473f882001-02-23 17:55:21 +00002531 * xmlDumpNotationTable:
2532 * @buf: the XML buffer output
2533 * @table: A notation table
2534 *
2535 * This will dump the content of the notation table as an XML DTD definition
2536 */
2537void
2538xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002539 if ((buf == NULL) || (table == NULL))
2540 return;
William M. Brack9e660592003-10-20 14:56:06 +00002541 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002542}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002543#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002544
2545/************************************************************************
2546 * *
2547 * IDs *
2548 * *
2549 ************************************************************************/
2550/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002551 * DICT_FREE:
2552 * @str: a string
2553 *
2554 * Free a string if it is not owned by the "dict" dictionnary in the
2555 * current scope
2556 */
2557#define DICT_FREE(str) \
2558 if ((str) && ((!dict) || \
2559 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2560 xmlFree((char *)(str));
2561
2562/**
Owen Taylor3473f882001-02-23 17:55:21 +00002563 * xmlFreeID:
2564 * @not: A id
2565 *
2566 * Deallocate the memory used by an id definition
2567 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002568static void
Owen Taylor3473f882001-02-23 17:55:21 +00002569xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002570 xmlDictPtr dict = NULL;
2571
Owen Taylor3473f882001-02-23 17:55:21 +00002572 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002573
2574 if (id->doc != NULL)
2575 dict = id->doc->dict;
2576
Owen Taylor3473f882001-02-23 17:55:21 +00002577 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002578 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002579 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002580 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002581 xmlFree(id);
2582}
2583
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002584
Owen Taylor3473f882001-02-23 17:55:21 +00002585/**
2586 * xmlAddID:
2587 * @ctxt: the validation context
2588 * @doc: pointer to the document
2589 * @value: the value name
2590 * @attr: the attribute holding the ID
2591 *
2592 * Register a new id declaration
2593 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002594 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002595 */
2596xmlIDPtr
2597xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2598 xmlAttrPtr attr) {
2599 xmlIDPtr ret;
2600 xmlIDTablePtr table;
2601
2602 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002603 return(NULL);
2604 }
2605 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002606 return(NULL);
2607 }
2608 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002609 return(NULL);
2610 }
2611
2612 /*
2613 * Create the ID table if needed.
2614 */
2615 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002616 if (table == NULL) {
2617 doc->ids = table = xmlHashCreateDict(0, doc->dict);
2618 }
Owen Taylor3473f882001-02-23 17:55:21 +00002619 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002620 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002621 "xmlAddID: Table creation failed!\n");
2622 return(NULL);
2623 }
2624
2625 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2626 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002627 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002628 return(NULL);
2629 }
2630
2631 /*
2632 * fill the structure.
2633 */
2634 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002635 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002636 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2637 /*
2638 * Operating in streaming mode, attr is gonna disapear
2639 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002640 if (doc->dict != NULL)
2641 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2642 else
2643 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002644 ret->attr = NULL;
2645 } else {
2646 ret->attr = attr;
2647 ret->name = NULL;
2648 }
2649 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002650
2651 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002652#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002653 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002654 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002655 */
Daniel Veillardd3669b22004-02-25 12:34:55 +00002656 if ((ctxt != NULL) && (ctxt->error != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002657 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2658 "ID %s already defined\n",
2659 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002660 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002661#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002662 xmlFreeID(ret);
2663 return(NULL);
2664 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002665 if (attr != NULL)
2666 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002667 return(ret);
2668}
2669
2670/**
2671 * xmlFreeIDTable:
2672 * @table: An id table
2673 *
2674 * Deallocate the memory used by an ID hash table.
2675 */
2676void
2677xmlFreeIDTable(xmlIDTablePtr table) {
2678 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2679}
2680
2681/**
2682 * xmlIsID:
2683 * @doc: the document
2684 * @elem: the element carrying the attribute
2685 * @attr: the attribute
2686 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002687 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002688 * then this is done if DTD loading has been requested. In the case
2689 * of HTML documents parsed with the HTML parser, then ID detection is
2690 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002691 *
2692 * Returns 0 or 1 depending on the lookup result
2693 */
2694int
2695xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2696 if (doc == NULL) return(0);
2697 if (attr == NULL) return(0);
2698 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2699 return(0);
2700 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard9ba8e382003-10-28 21:31:45 +00002701 if (((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2702 (xmlStrEqual(BAD_CAST "name", attr->name))) &&
2703 ((elem != NULL) && (!xmlStrEqual(elem->name, BAD_CAST "input"))))
Owen Taylor3473f882001-02-23 17:55:21 +00002704 return(1);
2705 return(0);
2706 } else {
2707 xmlAttributePtr attrDecl;
2708
2709 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002710 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002711 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002712 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002713
2714 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002715 if (fullname == NULL)
2716 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002717 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2718 attr->name);
2719 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2720 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2721 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002722 if ((fullname != fn) && (fullname != elem->name))
2723 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002724 } else {
2725 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2726 attr->name);
2727 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2728 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2729 attr->name);
2730 }
Owen Taylor3473f882001-02-23 17:55:21 +00002731
2732 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2733 return(1);
2734 }
2735 return(0);
2736}
2737
2738/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002739 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002740 * @doc: the document
2741 * @attr: the attribute
2742 *
2743 * Remove the given attribute from the ID table maintained internally.
2744 *
2745 * Returns -1 if the lookup failed and 0 otherwise
2746 */
2747int
2748xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002749 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002750 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002751 xmlChar *ID;
2752
2753 if (doc == NULL) return(-1);
2754 if (attr == NULL) return(-1);
2755 table = (xmlIDTablePtr) doc->ids;
2756 if (table == NULL)
2757 return(-1);
2758
2759 if (attr == NULL)
2760 return(-1);
2761 ID = xmlNodeListGetString(doc, attr->children, 1);
2762 if (ID == NULL)
2763 return(-1);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002764 id = xmlHashLookup(table, ID);
2765 if (id == NULL || id->attr != attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002766 xmlFree(ID);
2767 return(-1);
2768 }
Daniel Veillard91b955c2004-12-10 10:26:42 +00002769 xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID);
Owen Taylor3473f882001-02-23 17:55:21 +00002770 xmlFree(ID);
2771 return(0);
2772}
2773
2774/**
2775 * xmlGetID:
2776 * @doc: pointer to the document
2777 * @ID: the ID value
2778 *
2779 * Search the attribute declaring the given ID
2780 *
2781 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2782 */
2783xmlAttrPtr
2784xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2785 xmlIDTablePtr table;
2786 xmlIDPtr id;
2787
2788 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002789 return(NULL);
2790 }
2791
2792 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002793 return(NULL);
2794 }
2795
2796 table = (xmlIDTablePtr) doc->ids;
2797 if (table == NULL)
2798 return(NULL);
2799
2800 id = xmlHashLookup(table, ID);
2801 if (id == NULL)
2802 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002803 if (id->attr == NULL) {
2804 /*
2805 * We are operating on a stream, return a well known reference
2806 * since the attribute node doesn't exist anymore
2807 */
2808 return((xmlAttrPtr) doc);
2809 }
Owen Taylor3473f882001-02-23 17:55:21 +00002810 return(id->attr);
2811}
2812
2813/************************************************************************
2814 * *
2815 * Refs *
2816 * *
2817 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002818typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002819{
2820 xmlListPtr l;
2821 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002822} xmlRemoveMemo;
2823
2824typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2825
2826typedef struct xmlValidateMemo_t
2827{
2828 xmlValidCtxtPtr ctxt;
2829 const xmlChar *name;
2830} xmlValidateMemo;
2831
2832typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002833
2834/**
Owen Taylor3473f882001-02-23 17:55:21 +00002835 * xmlFreeRef:
2836 * @lk: A list link
2837 *
2838 * Deallocate the memory used by a ref definition
2839 */
2840static void
2841xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002842 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2843 if (ref == NULL) return;
2844 if (ref->value != NULL)
2845 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002846 if (ref->name != NULL)
2847 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002848 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002849}
2850
2851/**
2852 * xmlFreeRefList:
2853 * @list_ref: A list of references.
2854 *
2855 * Deallocate the memory used by a list of references
2856 */
2857static void
2858xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002859 if (list_ref == NULL) return;
2860 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002861}
2862
2863/**
2864 * xmlWalkRemoveRef:
2865 * @data: Contents of current link
2866 * @user: Value supplied by the user
2867 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002868 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002869 */
2870static int
2871xmlWalkRemoveRef(const void *data, const void *user)
2872{
Daniel Veillard37721922001-05-04 15:21:12 +00002873 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2874 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2875 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002876
Daniel Veillard37721922001-05-04 15:21:12 +00002877 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2878 xmlListRemoveFirst(ref_list, (void *)data);
2879 return 0;
2880 }
2881 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002882}
2883
2884/**
Daniel Veillard770075b2004-02-25 10:44:30 +00002885 * xmlDummyCompare
2886 * @data0: Value supplied by the user
2887 * @data1: Value supplied by the user
2888 *
2889 * Do nothing, return 0. Used to create unordered lists.
2890 */
2891static int
Daniel Veillardf54cd532004-02-25 11:52:31 +00002892xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2893 const void *data1 ATTRIBUTE_UNUSED)
Daniel Veillard770075b2004-02-25 10:44:30 +00002894{
2895 return (0);
2896}
2897
2898/**
Owen Taylor3473f882001-02-23 17:55:21 +00002899 * xmlAddRef:
2900 * @ctxt: the validation context
2901 * @doc: pointer to the document
2902 * @value: the value name
2903 * @attr: the attribute holding the Ref
2904 *
2905 * Register a new ref declaration
2906 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002907 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002908 */
2909xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002910xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002911 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002912 xmlRefPtr ret;
2913 xmlRefTablePtr table;
2914 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002915
Daniel Veillard37721922001-05-04 15:21:12 +00002916 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002917 return(NULL);
2918 }
2919 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002920 return(NULL);
2921 }
2922 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002923 return(NULL);
2924 }
Owen Taylor3473f882001-02-23 17:55:21 +00002925
Daniel Veillard37721922001-05-04 15:21:12 +00002926 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002927 * Create the Ref table if needed.
2928 */
Daniel Veillard37721922001-05-04 15:21:12 +00002929 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002930 if (table == NULL) {
2931 doc->refs = table = xmlHashCreateDict(0, doc->dict);
2932 }
Daniel Veillard37721922001-05-04 15:21:12 +00002933 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002934 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002935 "xmlAddRef: Table creation failed!\n");
2936 return(NULL);
2937 }
Owen Taylor3473f882001-02-23 17:55:21 +00002938
Daniel Veillard37721922001-05-04 15:21:12 +00002939 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2940 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002941 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002942 return(NULL);
2943 }
Owen Taylor3473f882001-02-23 17:55:21 +00002944
Daniel Veillard37721922001-05-04 15:21:12 +00002945 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002946 * fill the structure.
2947 */
Daniel Veillard37721922001-05-04 15:21:12 +00002948 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002949 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2950 /*
2951 * Operating in streaming mode, attr is gonna disapear
2952 */
2953 ret->name = xmlStrdup(attr->name);
2954 ret->attr = NULL;
2955 } else {
2956 ret->name = NULL;
2957 ret->attr = attr;
2958 }
2959 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002960
Daniel Veillard37721922001-05-04 15:21:12 +00002961 /* To add a reference :-
2962 * References are maintained as a list of references,
2963 * Lookup the entry, if no entry create new nodelist
2964 * Add the owning node to the NodeList
2965 * Return the ref
2966 */
Owen Taylor3473f882001-02-23 17:55:21 +00002967
Daniel Veillard37721922001-05-04 15:21:12 +00002968 if (NULL == (ref_list = xmlHashLookup(table, value))) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002969 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002970 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2971 "xmlAddRef: Reference list creation failed!\n",
2972 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002973 return(NULL);
2974 }
2975 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2976 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002977 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2978 "xmlAddRef: Reference list insertion failed!\n",
2979 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002980 return(NULL);
2981 }
2982 }
Daniel Veillard965983a2004-02-17 16:30:24 +00002983/* xmlListInsert(ref_list, ret); */
2984 xmlListAppend(ref_list, ret);
Daniel Veillard37721922001-05-04 15:21:12 +00002985 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002986}
2987
2988/**
2989 * xmlFreeRefTable:
2990 * @table: An ref table
2991 *
2992 * Deallocate the memory used by an Ref hash table.
2993 */
2994void
2995xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002996 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002997}
2998
2999/**
3000 * xmlIsRef:
3001 * @doc: the document
3002 * @elem: the element carrying the attribute
3003 * @attr: the attribute
3004 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003005 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00003006 * then this is simple, otherwise we use an heuristic: name Ref (upper
3007 * or lowercase).
3008 *
3009 * Returns 0 or 1 depending on the lookup result
3010 */
3011int
3012xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003013 if (attr == NULL)
3014 return(0);
3015 if (doc == NULL) {
3016 doc = attr->doc;
3017 if (doc == NULL) return(0);
3018 }
3019
Daniel Veillard37721922001-05-04 15:21:12 +00003020 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3021 return(0);
3022 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3023 /* TODO @@@ */
3024 return(0);
3025 } else {
3026 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00003027
Daniel Veillardce244ad2004-11-05 10:03:46 +00003028 if (elem == NULL) return(0);
Daniel Veillard37721922001-05-04 15:21:12 +00003029 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3030 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3031 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3032 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00003033
Daniel Veillard37721922001-05-04 15:21:12 +00003034 if ((attrDecl != NULL) &&
3035 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3036 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3037 return(1);
3038 }
3039 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003040}
3041
3042/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003043 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00003044 * @doc: the document
3045 * @attr: the attribute
3046 *
3047 * Remove the given attribute from the Ref table maintained internally.
3048 *
3049 * Returns -1 if the lookup failed and 0 otherwise
3050 */
3051int
3052xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00003053 xmlListPtr ref_list;
3054 xmlRefTablePtr table;
3055 xmlChar *ID;
3056 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00003057
Daniel Veillard37721922001-05-04 15:21:12 +00003058 if (doc == NULL) return(-1);
3059 if (attr == NULL) return(-1);
3060 table = (xmlRefTablePtr) doc->refs;
3061 if (table == NULL)
3062 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003063
Daniel Veillard37721922001-05-04 15:21:12 +00003064 if (attr == NULL)
3065 return(-1);
3066 ID = xmlNodeListGetString(doc, attr->children, 1);
3067 if (ID == NULL)
3068 return(-1);
3069 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00003070
Daniel Veillard37721922001-05-04 15:21:12 +00003071 if(ref_list == NULL) {
3072 xmlFree(ID);
3073 return (-1);
3074 }
3075 /* At this point, ref_list refers to a list of references which
3076 * have the same key as the supplied attr. Our list of references
3077 * is ordered by reference address and we don't have that information
3078 * here to use when removing. We'll have to walk the list and
3079 * check for a matching attribute, when we find one stop the walk
3080 * and remove the entry.
3081 * The list is ordered by reference, so that means we don't have the
3082 * key. Passing the list and the reference to the walker means we
3083 * will have enough data to be able to remove the entry.
3084 */
3085 target.l = ref_list;
3086 target.ap = attr;
3087
3088 /* Remove the supplied attr from our list */
3089 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00003090
Daniel Veillard37721922001-05-04 15:21:12 +00003091 /*If the list is empty then remove the list entry in the hash */
3092 if (xmlListEmpty(ref_list))
3093 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
3094 xmlFreeRefList);
3095 xmlFree(ID);
3096 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003097}
3098
3099/**
3100 * xmlGetRefs:
3101 * @doc: pointer to the document
3102 * @ID: the ID value
3103 *
3104 * Find the set of references for the supplied ID.
3105 *
3106 * Returns NULL if not found, otherwise node set for the ID.
3107 */
3108xmlListPtr
3109xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00003110 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00003111
Daniel Veillard37721922001-05-04 15:21:12 +00003112 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003113 return(NULL);
3114 }
Owen Taylor3473f882001-02-23 17:55:21 +00003115
Daniel Veillard37721922001-05-04 15:21:12 +00003116 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003117 return(NULL);
3118 }
Owen Taylor3473f882001-02-23 17:55:21 +00003119
Daniel Veillard37721922001-05-04 15:21:12 +00003120 table = (xmlRefTablePtr) doc->refs;
3121 if (table == NULL)
3122 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003123
Daniel Veillard37721922001-05-04 15:21:12 +00003124 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00003125}
3126
3127/************************************************************************
3128 * *
3129 * Routines for validity checking *
3130 * *
3131 ************************************************************************/
3132
3133/**
3134 * xmlGetDtdElementDesc:
3135 * @dtd: a pointer to the DtD to search
3136 * @name: the element name
3137 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003138 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003139 *
3140 * returns the xmlElementPtr if found or NULL
3141 */
3142
3143xmlElementPtr
3144xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3145 xmlElementTablePtr table;
3146 xmlElementPtr cur;
3147 xmlChar *uqname = NULL, *prefix = NULL;
3148
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00003149 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003150 if (dtd->elements == NULL)
3151 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003152 table = (xmlElementTablePtr) dtd->elements;
3153
3154 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003155 if (uqname != NULL)
3156 name = uqname;
3157 cur = xmlHashLookup2(table, name, prefix);
3158 if (prefix != NULL) xmlFree(prefix);
3159 if (uqname != NULL) xmlFree(uqname);
3160 return(cur);
3161}
3162/**
3163 * xmlGetDtdElementDesc2:
3164 * @dtd: a pointer to the DtD to search
3165 * @name: the element name
3166 * @create: create an empty description if not found
3167 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003168 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00003169 *
3170 * returns the xmlElementPtr if found or NULL
3171 */
3172
Daniel Veillard86fd5a72001-12-13 14:55:21 +00003173static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00003174xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3175 xmlElementTablePtr table;
3176 xmlElementPtr cur;
3177 xmlChar *uqname = NULL, *prefix = NULL;
3178
3179 if (dtd == NULL) return(NULL);
3180 if (dtd->elements == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003181 xmlDictPtr dict = NULL;
3182
3183 if (dtd->doc != NULL)
3184 dict = dtd->doc->dict;
3185
Daniel Veillarda10efa82001-04-18 13:09:01 +00003186 if (!create)
3187 return(NULL);
3188 /*
3189 * Create the Element table if needed.
3190 */
3191 table = (xmlElementTablePtr) dtd->elements;
3192 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003193 table = xmlHashCreateDict(0, dict);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003194 dtd->elements = (void *) table;
3195 }
3196 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003197 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003198 return(NULL);
3199 }
3200 }
3201 table = (xmlElementTablePtr) dtd->elements;
3202
3203 uqname = xmlSplitQName2(name, &prefix);
3204 if (uqname != NULL)
3205 name = uqname;
3206 cur = xmlHashLookup2(table, name, prefix);
3207 if ((cur == NULL) && (create)) {
3208 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3209 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003210 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003211 return(NULL);
3212 }
3213 memset(cur, 0, sizeof(xmlElement));
3214 cur->type = XML_ELEMENT_DECL;
3215
3216 /*
3217 * fill the structure.
3218 */
3219 cur->name = xmlStrdup(name);
3220 cur->prefix = xmlStrdup(prefix);
3221 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3222
3223 xmlHashAddEntry2(table, name, prefix, cur);
3224 }
3225 if (prefix != NULL) xmlFree(prefix);
3226 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003227 return(cur);
3228}
3229
3230/**
3231 * xmlGetDtdQElementDesc:
3232 * @dtd: a pointer to the DtD to search
3233 * @name: the element name
3234 * @prefix: the element namespace prefix
3235 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003236 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003237 *
3238 * returns the xmlElementPtr if found or NULL
3239 */
3240
Daniel Veillard48da9102001-08-07 01:10:10 +00003241xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003242xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3243 const xmlChar *prefix) {
3244 xmlElementTablePtr table;
3245
3246 if (dtd == NULL) return(NULL);
3247 if (dtd->elements == NULL) return(NULL);
3248 table = (xmlElementTablePtr) dtd->elements;
3249
3250 return(xmlHashLookup2(table, name, prefix));
3251}
3252
3253/**
3254 * xmlGetDtdAttrDesc:
3255 * @dtd: a pointer to the DtD to search
3256 * @elem: the element name
3257 * @name: the attribute name
3258 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003259 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003260 * this element.
3261 *
3262 * returns the xmlAttributePtr if found or NULL
3263 */
3264
3265xmlAttributePtr
3266xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3267 xmlAttributeTablePtr table;
3268 xmlAttributePtr cur;
3269 xmlChar *uqname = NULL, *prefix = NULL;
3270
3271 if (dtd == NULL) return(NULL);
3272 if (dtd->attributes == NULL) return(NULL);
3273
3274 table = (xmlAttributeTablePtr) dtd->attributes;
3275 if (table == NULL)
3276 return(NULL);
3277
3278 uqname = xmlSplitQName2(name, &prefix);
3279
3280 if (uqname != NULL) {
3281 cur = xmlHashLookup3(table, uqname, prefix, elem);
3282 if (prefix != NULL) xmlFree(prefix);
3283 if (uqname != NULL) xmlFree(uqname);
3284 } else
3285 cur = xmlHashLookup3(table, name, NULL, elem);
3286 return(cur);
3287}
3288
3289/**
3290 * xmlGetDtdQAttrDesc:
3291 * @dtd: a pointer to the DtD to search
3292 * @elem: the element name
3293 * @name: the attribute name
3294 * @prefix: the attribute namespace prefix
3295 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003296 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003297 * this element.
3298 *
3299 * returns the xmlAttributePtr if found or NULL
3300 */
3301
Daniel Veillard48da9102001-08-07 01:10:10 +00003302xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003303xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3304 const xmlChar *prefix) {
3305 xmlAttributeTablePtr table;
3306
3307 if (dtd == NULL) return(NULL);
3308 if (dtd->attributes == NULL) return(NULL);
3309 table = (xmlAttributeTablePtr) dtd->attributes;
3310
3311 return(xmlHashLookup3(table, name, prefix, elem));
3312}
3313
3314/**
3315 * xmlGetDtdNotationDesc:
3316 * @dtd: a pointer to the DtD to search
3317 * @name: the notation name
3318 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003319 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003320 *
3321 * returns the xmlNotationPtr if found or NULL
3322 */
3323
3324xmlNotationPtr
3325xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3326 xmlNotationTablePtr table;
3327
3328 if (dtd == NULL) return(NULL);
3329 if (dtd->notations == NULL) return(NULL);
3330 table = (xmlNotationTablePtr) dtd->notations;
3331
3332 return(xmlHashLookup(table, name));
3333}
3334
Daniel Veillardf54cd532004-02-25 11:52:31 +00003335#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003336/**
3337 * xmlValidateNotationUse:
3338 * @ctxt: the validation context
3339 * @doc: the document
3340 * @notationName: the notation name to check
3341 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003342 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003343 * - [ VC: Notation Declared ]
3344 *
3345 * returns 1 if valid or 0 otherwise
3346 */
3347
3348int
3349xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3350 const xmlChar *notationName) {
3351 xmlNotationPtr notaDecl;
3352 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3353
3354 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3355 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3356 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3357
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003358 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003359 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3360 "NOTATION %s is not declared\n",
3361 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003362 return(0);
3363 }
3364 return(1);
3365}
Daniel Veillardf54cd532004-02-25 11:52:31 +00003366#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003367
3368/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003369 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003370 * @doc: the document
3371 * @name: the element name
3372 *
3373 * Search in the DtDs whether an element accept Mixed content (or ANY)
3374 * basically if it is supposed to accept text childs
3375 *
3376 * returns 0 if no, 1 if yes, and -1 if no element description is available
3377 */
3378
3379int
3380xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3381 xmlElementPtr elemDecl;
3382
3383 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3384
3385 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3386 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3387 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3388 if (elemDecl == NULL) return(-1);
3389 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003390 case XML_ELEMENT_TYPE_UNDEFINED:
3391 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003392 case XML_ELEMENT_TYPE_ELEMENT:
3393 return(0);
3394 case XML_ELEMENT_TYPE_EMPTY:
3395 /*
3396 * return 1 for EMPTY since we want VC error to pop up
3397 * on <empty> </empty> for example
3398 */
3399 case XML_ELEMENT_TYPE_ANY:
3400 case XML_ELEMENT_TYPE_MIXED:
3401 return(1);
3402 }
3403 return(1);
3404}
3405
Daniel Veillard4432df22003-09-28 18:58:27 +00003406#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003407/**
3408 * xmlValidateNameValue:
3409 * @value: an Name value
3410 *
3411 * Validate that the given value match Name production
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 +00003417xmlValidateNameValue(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;
3425 if (!IS_LETTER(val) && (val != '_') &&
3426 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003427 return(0);
3428 }
3429
Daniel Veillardd8224e02002-01-13 15:43:22 +00003430 val = xmlStringCurrentChar(NULL, cur, &len);
3431 cur += len;
3432 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3433 (val == '.') || (val == '-') ||
3434 (val == '_') || (val == ':') ||
3435 (IS_COMBINING(val)) ||
3436 (IS_EXTENDER(val))) {
3437 val = xmlStringCurrentChar(NULL, cur, &len);
3438 cur += len;
3439 }
Owen Taylor3473f882001-02-23 17:55:21 +00003440
Daniel Veillardd8224e02002-01-13 15:43:22 +00003441 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003442
3443 return(1);
3444}
3445
3446/**
3447 * xmlValidateNamesValue:
3448 * @value: an Names value
3449 *
3450 * Validate that the given value match Names production
3451 *
3452 * returns 1 if valid or 0 otherwise
3453 */
3454
Daniel Veillard9b731d72002-04-14 12:56:08 +00003455int
Owen Taylor3473f882001-02-23 17:55:21 +00003456xmlValidateNamesValue(const xmlChar *value) {
3457 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003458 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003459
3460 if (value == NULL) return(0);
3461 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003462 val = xmlStringCurrentChar(NULL, cur, &len);
3463 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003464
Daniel Veillardd8224e02002-01-13 15:43:22 +00003465 if (!IS_LETTER(val) && (val != '_') &&
3466 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003467 return(0);
3468 }
3469
Daniel Veillardd8224e02002-01-13 15:43:22 +00003470 val = xmlStringCurrentChar(NULL, cur, &len);
3471 cur += len;
3472 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3473 (val == '.') || (val == '-') ||
3474 (val == '_') || (val == ':') ||
3475 (IS_COMBINING(val)) ||
3476 (IS_EXTENDER(val))) {
3477 val = xmlStringCurrentChar(NULL, cur, &len);
3478 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003479 }
3480
Daniel Veillard807b4de2004-09-26 14:42:56 +00003481 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3482 while (val == 0x20) {
3483 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003484 val = xmlStringCurrentChar(NULL, cur, &len);
3485 cur += len;
3486 }
3487
3488 if (!IS_LETTER(val) && (val != '_') &&
3489 (val != ':')) {
3490 return(0);
3491 }
3492 val = xmlStringCurrentChar(NULL, cur, &len);
3493 cur += len;
3494
3495 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3496 (val == '.') || (val == '-') ||
3497 (val == '_') || (val == ':') ||
3498 (IS_COMBINING(val)) ||
3499 (IS_EXTENDER(val))) {
3500 val = xmlStringCurrentChar(NULL, cur, &len);
3501 cur += len;
3502 }
3503 }
3504
3505 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003506
3507 return(1);
3508}
3509
3510/**
3511 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003512 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003513 *
3514 * Validate that the given value match Nmtoken production
3515 *
3516 * [ VC: Name Token ]
3517 *
3518 * returns 1 if valid or 0 otherwise
3519 */
3520
Daniel Veillard9b731d72002-04-14 12:56:08 +00003521int
Owen Taylor3473f882001-02-23 17:55:21 +00003522xmlValidateNmtokenValue(const xmlChar *value) {
3523 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003524 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003525
3526 if (value == NULL) return(0);
3527 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003528 val = xmlStringCurrentChar(NULL, cur, &len);
3529 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003530
Daniel Veillardd8224e02002-01-13 15:43:22 +00003531 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3532 (val != '.') && (val != '-') &&
3533 (val != '_') && (val != ':') &&
3534 (!IS_COMBINING(val)) &&
3535 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003536 return(0);
3537
Daniel Veillardd8224e02002-01-13 15:43:22 +00003538 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3539 (val == '.') || (val == '-') ||
3540 (val == '_') || (val == ':') ||
3541 (IS_COMBINING(val)) ||
3542 (IS_EXTENDER(val))) {
3543 val = xmlStringCurrentChar(NULL, cur, &len);
3544 cur += len;
3545 }
Owen Taylor3473f882001-02-23 17:55:21 +00003546
Daniel Veillardd8224e02002-01-13 15:43:22 +00003547 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003548
3549 return(1);
3550}
3551
3552/**
3553 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003554 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003555 *
3556 * Validate that the given value match Nmtokens production
3557 *
3558 * [ VC: Name Token ]
3559 *
3560 * returns 1 if valid or 0 otherwise
3561 */
3562
Daniel Veillard9b731d72002-04-14 12:56:08 +00003563int
Owen Taylor3473f882001-02-23 17:55:21 +00003564xmlValidateNmtokensValue(const xmlChar *value) {
3565 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003566 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003567
3568 if (value == NULL) return(0);
3569 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003570 val = xmlStringCurrentChar(NULL, cur, &len);
3571 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003572
Daniel Veillardd8224e02002-01-13 15:43:22 +00003573 while (IS_BLANK(val)) {
3574 val = xmlStringCurrentChar(NULL, cur, &len);
3575 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003576 }
3577
Daniel Veillardd8224e02002-01-13 15:43:22 +00003578 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3579 (val != '.') && (val != '-') &&
3580 (val != '_') && (val != ':') &&
3581 (!IS_COMBINING(val)) &&
3582 (!IS_EXTENDER(val)))
3583 return(0);
3584
3585 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3586 (val == '.') || (val == '-') ||
3587 (val == '_') || (val == ':') ||
3588 (IS_COMBINING(val)) ||
3589 (IS_EXTENDER(val))) {
3590 val = xmlStringCurrentChar(NULL, cur, &len);
3591 cur += len;
3592 }
3593
Daniel Veillard807b4de2004-09-26 14:42:56 +00003594 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3595 while (val == 0x20) {
3596 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003597 val = xmlStringCurrentChar(NULL, cur, &len);
3598 cur += len;
3599 }
3600 if (val == 0) return(1);
3601
3602 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3603 (val != '.') && (val != '-') &&
3604 (val != '_') && (val != ':') &&
3605 (!IS_COMBINING(val)) &&
3606 (!IS_EXTENDER(val)))
3607 return(0);
3608
3609 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3610 (val == '.') || (val == '-') ||
3611 (val == '_') || (val == ':') ||
3612 (IS_COMBINING(val)) ||
3613 (IS_EXTENDER(val))) {
3614 val = xmlStringCurrentChar(NULL, cur, &len);
3615 cur += len;
3616 }
3617 }
3618
3619 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003620
3621 return(1);
3622}
3623
3624/**
3625 * xmlValidateNotationDecl:
3626 * @ctxt: the validation context
3627 * @doc: a document instance
3628 * @nota: a notation definition
3629 *
3630 * Try to validate a single notation definition
3631 * basically it does the following checks as described by the
3632 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003633 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003634 * But this function get called anyway ...
3635 *
3636 * returns 1 if valid or 0 otherwise
3637 */
3638
3639int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003640xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3641 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003642 int ret = 1;
3643
3644 return(ret);
3645}
3646
3647/**
3648 * xmlValidateAttributeValue:
3649 * @type: an attribute type
3650 * @value: an attribute value
3651 *
3652 * Validate that the given attribute value match the proper production
3653 *
3654 * [ VC: ID ]
3655 * Values of type ID must match the Name production....
3656 *
3657 * [ VC: IDREF ]
3658 * Values of type IDREF must match the Name production, and values
3659 * of type IDREFS must match Names ...
3660 *
3661 * [ VC: Entity Name ]
3662 * Values of type ENTITY must match the Name production, values
3663 * of type ENTITIES must match Names ...
3664 *
3665 * [ VC: Name Token ]
3666 * Values of type NMTOKEN must match the Nmtoken production; values
3667 * of type NMTOKENS must match Nmtokens.
3668 *
3669 * returns 1 if valid or 0 otherwise
3670 */
3671
3672int
3673xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3674 switch (type) {
3675 case XML_ATTRIBUTE_ENTITIES:
3676 case XML_ATTRIBUTE_IDREFS:
3677 return(xmlValidateNamesValue(value));
3678 case XML_ATTRIBUTE_ENTITY:
3679 case XML_ATTRIBUTE_IDREF:
3680 case XML_ATTRIBUTE_ID:
3681 case XML_ATTRIBUTE_NOTATION:
3682 return(xmlValidateNameValue(value));
3683 case XML_ATTRIBUTE_NMTOKENS:
3684 case XML_ATTRIBUTE_ENUMERATION:
3685 return(xmlValidateNmtokensValue(value));
3686 case XML_ATTRIBUTE_NMTOKEN:
3687 return(xmlValidateNmtokenValue(value));
3688 case XML_ATTRIBUTE_CDATA:
3689 break;
3690 }
3691 return(1);
3692}
3693
3694/**
3695 * xmlValidateAttributeValue2:
3696 * @ctxt: the validation context
3697 * @doc: the document
3698 * @name: the attribute name (used for error reporting only)
3699 * @type: the attribute type
3700 * @value: the attribute value
3701 *
3702 * Validate that the given attribute value match a given type.
3703 * This typically cannot be done before having finished parsing
3704 * the subsets.
3705 *
3706 * [ VC: IDREF ]
3707 * Values of type IDREF must match one of the declared IDs
3708 * Values of type IDREFS must match a sequence of the declared IDs
3709 * each Name must match the value of an ID attribute on some element
3710 * in the XML document; i.e. IDREF values must match the value of
3711 * some ID attribute
3712 *
3713 * [ VC: Entity Name ]
3714 * Values of type ENTITY must match one declared entity
3715 * Values of type ENTITIES must match a sequence of declared entities
3716 *
3717 * [ VC: Notation Attributes ]
3718 * all notation names in the declaration must be declared.
3719 *
3720 * returns 1 if valid or 0 otherwise
3721 */
3722
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003723static int
Owen Taylor3473f882001-02-23 17:55:21 +00003724xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3725 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3726 int ret = 1;
3727 switch (type) {
3728 case XML_ATTRIBUTE_IDREFS:
3729 case XML_ATTRIBUTE_IDREF:
3730 case XML_ATTRIBUTE_ID:
3731 case XML_ATTRIBUTE_NMTOKENS:
3732 case XML_ATTRIBUTE_ENUMERATION:
3733 case XML_ATTRIBUTE_NMTOKEN:
3734 case XML_ATTRIBUTE_CDATA:
3735 break;
3736 case XML_ATTRIBUTE_ENTITY: {
3737 xmlEntityPtr ent;
3738
3739 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003740 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003741 if ((ent == NULL) && (doc->standalone == 1)) {
3742 doc->standalone = 0;
3743 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003744 }
Owen Taylor3473f882001-02-23 17:55:21 +00003745 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003746 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3747 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003748 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003749 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003750 ret = 0;
3751 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003752 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3753 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003754 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003755 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003756 ret = 0;
3757 }
3758 break;
3759 }
3760 case XML_ATTRIBUTE_ENTITIES: {
3761 xmlChar *dup, *nam = NULL, *cur, save;
3762 xmlEntityPtr ent;
3763
3764 dup = xmlStrdup(value);
3765 if (dup == NULL)
3766 return(0);
3767 cur = dup;
3768 while (*cur != 0) {
3769 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003770 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003771 save = *cur;
3772 *cur = 0;
3773 ent = xmlGetDocEntity(doc, nam);
3774 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003775 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3776 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003777 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003778 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003779 ret = 0;
3780 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003781 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3782 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003783 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003784 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003785 ret = 0;
3786 }
3787 if (save == 0)
3788 break;
3789 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003790 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003791 }
3792 xmlFree(dup);
3793 break;
3794 }
3795 case XML_ATTRIBUTE_NOTATION: {
3796 xmlNotationPtr nota;
3797
3798 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3799 if ((nota == NULL) && (doc->extSubset != NULL))
3800 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3801
3802 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003803 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3804 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003805 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003806 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003807 ret = 0;
3808 }
3809 break;
3810 }
3811 }
3812 return(ret);
3813}
3814
3815/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003816 * xmlValidCtxtNormalizeAttributeValue:
3817 * @ctxt: the validation context
3818 * @doc: the document
3819 * @elem: the parent
3820 * @name: the attribute name
3821 * @value: the attribute value
3822 * @ctxt: the validation context or NULL
3823 *
3824 * Does the validation related extra step of the normalization of attribute
3825 * values:
3826 *
3827 * If the declared value is not CDATA, then the XML processor must further
3828 * process the normalized attribute value by discarding any leading and
3829 * trailing space (#x20) characters, and by replacing sequences of space
3830 * (#x20) characters by single space (#x20) character.
3831 *
3832 * Also check VC: Standalone Document Declaration in P32, and update
3833 * ctxt->valid accordingly
3834 *
3835 * returns a new normalized string if normalization is needed, NULL otherwise
3836 * the caller must free the returned value.
3837 */
3838
3839xmlChar *
3840xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3841 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3842 xmlChar *ret, *dst;
3843 const xmlChar *src;
3844 xmlAttributePtr attrDecl = NULL;
3845 int extsubset = 0;
3846
3847 if (doc == NULL) return(NULL);
3848 if (elem == NULL) return(NULL);
3849 if (name == NULL) return(NULL);
3850 if (value == NULL) return(NULL);
3851
3852 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003853 xmlChar fn[50];
3854 xmlChar *fullname;
3855
3856 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3857 if (fullname == NULL)
3858 return(0);
3859 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003860 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003861 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003862 if (attrDecl != NULL)
3863 extsubset = 1;
3864 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003865 if ((fullname != fn) && (fullname != elem->name))
3866 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003867 }
3868 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3869 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3870 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3871 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3872 if (attrDecl != NULL)
3873 extsubset = 1;
3874 }
3875
3876 if (attrDecl == NULL)
3877 return(NULL);
3878 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3879 return(NULL);
3880
3881 ret = xmlStrdup(value);
3882 if (ret == NULL)
3883 return(NULL);
3884 src = value;
3885 dst = ret;
3886 while (*src == 0x20) src++;
3887 while (*src != 0) {
3888 if (*src == 0x20) {
3889 while (*src == 0x20) src++;
3890 if (*src != 0)
3891 *dst++ = 0x20;
3892 } else {
3893 *dst++ = *src++;
3894 }
3895 }
3896 *dst = 0;
3897 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003898 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003899"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003900 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003901 ctxt->valid = 0;
3902 }
3903 return(ret);
3904}
3905
3906/**
Owen Taylor3473f882001-02-23 17:55:21 +00003907 * xmlValidNormalizeAttributeValue:
3908 * @doc: the document
3909 * @elem: the parent
3910 * @name: the attribute name
3911 * @value: the attribute value
3912 *
3913 * Does the validation related extra step of the normalization of attribute
3914 * values:
3915 *
3916 * If the declared value is not CDATA, then the XML processor must further
3917 * process the normalized attribute value by discarding any leading and
3918 * trailing space (#x20) characters, and by replacing sequences of space
3919 * (#x20) characters by single space (#x20) character.
3920 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003921 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003922 * the caller must free the returned value.
3923 */
3924
3925xmlChar *
3926xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3927 const xmlChar *name, const xmlChar *value) {
3928 xmlChar *ret, *dst;
3929 const xmlChar *src;
3930 xmlAttributePtr attrDecl = NULL;
3931
3932 if (doc == NULL) return(NULL);
3933 if (elem == NULL) return(NULL);
3934 if (name == NULL) return(NULL);
3935 if (value == NULL) return(NULL);
3936
3937 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003938 xmlChar fn[50];
3939 xmlChar *fullname;
3940
3941 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3942 if (fullname == NULL)
3943 return(0);
3944 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003945 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003946 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3947 if ((fullname != fn) && (fullname != elem->name))
3948 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003949 }
3950 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3951 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3952 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3953
3954 if (attrDecl == NULL)
3955 return(NULL);
3956 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3957 return(NULL);
3958
3959 ret = xmlStrdup(value);
3960 if (ret == NULL)
3961 return(NULL);
3962 src = value;
3963 dst = ret;
3964 while (*src == 0x20) src++;
3965 while (*src != 0) {
3966 if (*src == 0x20) {
3967 while (*src == 0x20) src++;
3968 if (*src != 0)
3969 *dst++ = 0x20;
3970 } else {
3971 *dst++ = *src++;
3972 }
3973 }
3974 *dst = 0;
3975 return(ret);
3976}
3977
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003978static void
Owen Taylor3473f882001-02-23 17:55:21 +00003979xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003980 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003981 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3982}
3983
3984/**
3985 * xmlValidateAttributeDecl:
3986 * @ctxt: the validation context
3987 * @doc: a document instance
3988 * @attr: an attribute definition
3989 *
3990 * Try to validate a single attribute definition
3991 * basically it does the following checks as described by the
3992 * XML-1.0 recommendation:
3993 * - [ VC: Attribute Default Legal ]
3994 * - [ VC: Enumeration ]
3995 * - [ VC: ID Attribute Default ]
3996 *
3997 * The ID/IDREF uniqueness and matching are done separately
3998 *
3999 * returns 1 if valid or 0 otherwise
4000 */
4001
4002int
4003xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4004 xmlAttributePtr attr) {
4005 int ret = 1;
4006 int val;
4007 CHECK_DTD;
4008 if(attr == NULL) return(1);
4009
4010 /* Attribute Default Legal */
4011 /* Enumeration */
4012 if (attr->defaultValue != NULL) {
4013 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
4014 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004015 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004016 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004017 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004018 }
4019 ret &= val;
4020 }
4021
4022 /* ID Attribute Default */
4023 if ((attr->atype == XML_ATTRIBUTE_ID)&&
4024 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4025 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004026 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004027 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004028 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004029 ret = 0;
4030 }
4031
4032 /* One ID per Element Type */
4033 if (attr->atype == XML_ATTRIBUTE_ID) {
4034 int nbId;
4035
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004036 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00004037 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4038 attr->elem);
4039 if (elem != NULL) {
4040 nbId = xmlScanIDAttributeDecl(NULL, elem);
4041 } else {
4042 xmlAttributeTablePtr table;
4043
4044 /*
4045 * The attribute may be declared in the internal subset and the
4046 * element in the external subset.
4047 */
4048 nbId = 0;
4049 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4050 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
4051 xmlValidateAttributeIdCallback, &nbId);
4052 }
4053 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004054
4055 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004056 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4057 attr->elem, nbId, attr->name);
4058 } else if (doc->extSubset != NULL) {
4059 int extId = 0;
4060 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4061 if (elem != NULL) {
4062 extId = xmlScanIDAttributeDecl(NULL, elem);
4063 }
4064 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004065 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004066 "Element %s has %d ID attribute defined in the external subset : %s\n",
4067 attr->elem, extId, attr->name);
4068 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004069 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004070"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004071 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004072 }
4073 }
4074 }
4075
4076 /* Validity Constraint: Enumeration */
4077 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4078 xmlEnumerationPtr tree = attr->tree;
4079 while (tree != NULL) {
4080 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4081 tree = tree->next;
4082 }
4083 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004084 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004085"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004086 attr->defaultValue, attr->name, attr->elem);
4087 ret = 0;
4088 }
4089 }
4090
4091 return(ret);
4092}
4093
4094/**
4095 * xmlValidateElementDecl:
4096 * @ctxt: the validation context
4097 * @doc: a document instance
4098 * @elem: an element definition
4099 *
4100 * Try to validate a single element definition
4101 * basically it does the following checks as described by the
4102 * XML-1.0 recommendation:
4103 * - [ VC: One ID per Element Type ]
4104 * - [ VC: No Duplicate Types ]
4105 * - [ VC: Unique Element Type Declaration ]
4106 *
4107 * returns 1 if valid or 0 otherwise
4108 */
4109
4110int
4111xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4112 xmlElementPtr elem) {
4113 int ret = 1;
4114 xmlElementPtr tst;
4115
4116 CHECK_DTD;
4117
4118 if (elem == NULL) return(1);
4119
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004120#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00004121#ifdef LIBXML_REGEXP_ENABLED
4122 /* Build the regexp associated to the content model */
4123 ret = xmlValidBuildContentModel(ctxt, elem);
4124#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004125#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00004126
Owen Taylor3473f882001-02-23 17:55:21 +00004127 /* No Duplicate Types */
4128 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4129 xmlElementContentPtr cur, next;
4130 const xmlChar *name;
4131
4132 cur = elem->content;
4133 while (cur != NULL) {
4134 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4135 if (cur->c1 == NULL) break;
4136 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4137 name = cur->c1->name;
4138 next = cur->c2;
4139 while (next != NULL) {
4140 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00004141 if ((xmlStrEqual(next->name, name)) &&
4142 (xmlStrEqual(next->prefix, cur->prefix))) {
4143 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004144 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00004145 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004146 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004147 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004148 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004149 "Definition of %s has duplicate references of %s:%s\n",
4150 elem->name, cur->prefix, name);
4151 }
Owen Taylor3473f882001-02-23 17:55:21 +00004152 ret = 0;
4153 }
4154 break;
4155 }
4156 if (next->c1 == NULL) break;
4157 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00004158 if ((xmlStrEqual(next->c1->name, name)) &&
4159 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
4160 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004161 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004162 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004163 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004164 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004165 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004166 "Definition of %s has duplicate references to %s:%s\n",
4167 elem->name, cur->prefix, name);
4168 }
Owen Taylor3473f882001-02-23 17:55:21 +00004169 ret = 0;
4170 }
4171 next = next->c2;
4172 }
4173 }
4174 cur = cur->c2;
4175 }
4176 }
4177
4178 /* VC: Unique Element Type Declaration */
4179 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004180 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004181 ((tst->prefix == elem->prefix) ||
4182 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004183 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004184 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4185 "Redefinition of element %s\n",
4186 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004187 ret = 0;
4188 }
4189 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004190 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004191 ((tst->prefix == elem->prefix) ||
4192 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004193 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004194 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4195 "Redefinition of element %s\n",
4196 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004197 ret = 0;
4198 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004199 /* One ID per Element Type
4200 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004201 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4202 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004203 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004204 return(ret);
4205}
4206
4207/**
4208 * xmlValidateOneAttribute:
4209 * @ctxt: the validation context
4210 * @doc: a document instance
4211 * @elem: an element instance
4212 * @attr: an attribute instance
4213 * @value: the attribute value (without entities processing)
4214 *
4215 * Try to validate a single attribute for an element
4216 * basically it does the following checks as described by the
4217 * XML-1.0 recommendation:
4218 * - [ VC: Attribute Value Type ]
4219 * - [ VC: Fixed Attribute Default ]
4220 * - [ VC: Entity Name ]
4221 * - [ VC: Name Token ]
4222 * - [ VC: ID ]
4223 * - [ VC: IDREF ]
4224 * - [ VC: Entity Name ]
4225 * - [ VC: Notation Attributes ]
4226 *
4227 * The ID/IDREF uniqueness and matching are done separately
4228 *
4229 * returns 1 if valid or 0 otherwise
4230 */
4231
4232int
4233xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004234 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4235{
Owen Taylor3473f882001-02-23 17:55:21 +00004236 xmlAttributePtr attrDecl = NULL;
4237 int val;
4238 int ret = 1;
4239
4240 CHECK_DTD;
4241 if ((elem == NULL) || (elem->name == NULL)) return(0);
4242 if ((attr == NULL) || (attr->name == NULL)) return(0);
4243
4244 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004245 xmlChar fn[50];
4246 xmlChar *fullname;
4247
4248 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4249 if (fullname == NULL)
4250 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004251 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004252 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004253 attr->name, attr->ns->prefix);
4254 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004255 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004256 attr->name, attr->ns->prefix);
4257 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004258 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004259 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4260 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004261 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004262 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004263 if ((fullname != fn) && (fullname != elem->name))
4264 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004265 }
4266 if (attrDecl == NULL) {
4267 if (attr->ns != NULL) {
4268 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4269 attr->name, attr->ns->prefix);
4270 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4271 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4272 attr->name, attr->ns->prefix);
4273 } else {
4274 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4275 elem->name, attr->name);
4276 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4277 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4278 elem->name, attr->name);
4279 }
4280 }
4281
4282
4283 /* Validity Constraint: Attribute Value Type */
4284 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004285 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004286 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004287 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004288 return(0);
4289 }
4290 attr->atype = attrDecl->atype;
4291
4292 val = xmlValidateAttributeValue(attrDecl->atype, value);
4293 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004294 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004295 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004296 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004297 ret = 0;
4298 }
4299
4300 /* Validity constraint: Fixed Attribute Default */
4301 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4302 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004303 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004304 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004305 attr->name, elem->name, attrDecl->defaultValue);
4306 ret = 0;
4307 }
4308 }
4309
4310 /* Validity Constraint: ID uniqueness */
4311 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4312 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4313 ret = 0;
4314 }
4315
4316 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4317 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4318 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4319 ret = 0;
4320 }
4321
4322 /* Validity Constraint: Notation Attributes */
4323 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4324 xmlEnumerationPtr tree = attrDecl->tree;
4325 xmlNotationPtr nota;
4326
4327 /* First check that the given NOTATION was declared */
4328 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4329 if (nota == NULL)
4330 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4331
4332 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004333 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004334 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004335 value, attr->name, elem->name);
4336 ret = 0;
4337 }
4338
4339 /* Second, verify that it's among the list */
4340 while (tree != NULL) {
4341 if (xmlStrEqual(tree->name, value)) break;
4342 tree = tree->next;
4343 }
4344 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004345 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004346"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004347 value, attr->name, elem->name);
4348 ret = 0;
4349 }
4350 }
4351
4352 /* Validity Constraint: Enumeration */
4353 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4354 xmlEnumerationPtr tree = attrDecl->tree;
4355 while (tree != NULL) {
4356 if (xmlStrEqual(tree->name, value)) break;
4357 tree = tree->next;
4358 }
4359 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004360 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004361 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004362 value, attr->name, elem->name);
4363 ret = 0;
4364 }
4365 }
4366
4367 /* Fixed Attribute Default */
4368 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4369 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004370 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004371 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004372 attr->name, elem->name, attrDecl->defaultValue);
4373 ret = 0;
4374 }
4375
4376 /* Extra check for the attribute value */
4377 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4378 attrDecl->atype, value);
4379
4380 return(ret);
4381}
4382
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004383/**
4384 * xmlValidateOneNamespace:
4385 * @ctxt: the validation context
4386 * @doc: a document instance
4387 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004388 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004389 * @ns: an namespace declaration instance
4390 * @value: the attribute value (without entities processing)
4391 *
4392 * Try to validate a single namespace declaration for an element
4393 * basically it does the following checks as described by the
4394 * XML-1.0 recommendation:
4395 * - [ VC: Attribute Value Type ]
4396 * - [ VC: Fixed Attribute Default ]
4397 * - [ VC: Entity Name ]
4398 * - [ VC: Name Token ]
4399 * - [ VC: ID ]
4400 * - [ VC: IDREF ]
4401 * - [ VC: Entity Name ]
4402 * - [ VC: Notation Attributes ]
4403 *
4404 * The ID/IDREF uniqueness and matching are done separately
4405 *
4406 * returns 1 if valid or 0 otherwise
4407 */
4408
4409int
4410xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4411xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4412 /* xmlElementPtr elemDecl; */
4413 xmlAttributePtr attrDecl = NULL;
4414 int val;
4415 int ret = 1;
4416
4417 CHECK_DTD;
4418 if ((elem == NULL) || (elem->name == NULL)) return(0);
4419 if ((ns == NULL) || (ns->href == NULL)) return(0);
4420
4421 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004422 xmlChar fn[50];
4423 xmlChar *fullname;
4424
4425 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4426 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004427 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004428 return(0);
4429 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004430 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004431 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004432 ns->prefix, BAD_CAST "xmlns");
4433 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004434 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004435 ns->prefix, BAD_CAST "xmlns");
4436 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004437 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004438 BAD_CAST "xmlns");
4439 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004440 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004441 BAD_CAST "xmlns");
4442 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004443 if ((fullname != fn) && (fullname != elem->name))
4444 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004445 }
4446 if (attrDecl == NULL) {
4447 if (ns->prefix != NULL) {
4448 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4449 ns->prefix, BAD_CAST "xmlns");
4450 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4451 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4452 ns->prefix, BAD_CAST "xmlns");
4453 } else {
4454 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4455 elem->name, BAD_CAST "xmlns");
4456 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4457 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4458 elem->name, BAD_CAST "xmlns");
4459 }
4460 }
4461
4462
4463 /* Validity Constraint: Attribute Value Type */
4464 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004465 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004466 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004467 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004468 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004469 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004470 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004471 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004472 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004473 }
4474 return(0);
4475 }
4476
4477 val = xmlValidateAttributeValue(attrDecl->atype, value);
4478 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004479 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004480 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004481 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004482 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004483 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004484 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004485 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004486 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004487 }
4488 ret = 0;
4489 }
4490
4491 /* Validity constraint: Fixed Attribute Default */
4492 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4493 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004494 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004495 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004496 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4497 ns->prefix, elem->name, attrDecl->defaultValue);
4498 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004499 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004500 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004501 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004502 }
4503 ret = 0;
4504 }
4505 }
4506
4507 /* Validity Constraint: ID uniqueness */
4508 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4509 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4510 ret = 0;
4511 }
4512
4513 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4514 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4515 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4516 ret = 0;
4517 }
4518
4519 /* Validity Constraint: Notation Attributes */
4520 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4521 xmlEnumerationPtr tree = attrDecl->tree;
4522 xmlNotationPtr nota;
4523
4524 /* First check that the given NOTATION was declared */
4525 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4526 if (nota == NULL)
4527 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4528
4529 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004530 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004531 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004532 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4533 value, ns->prefix, elem->name);
4534 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004535 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004536 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004537 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004538 }
4539 ret = 0;
4540 }
4541
4542 /* Second, verify that it's among the list */
4543 while (tree != NULL) {
4544 if (xmlStrEqual(tree->name, value)) break;
4545 tree = tree->next;
4546 }
4547 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004548 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004549 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004550"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4551 value, ns->prefix, elem->name);
4552 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004553 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004554"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004555 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004556 }
4557 ret = 0;
4558 }
4559 }
4560
4561 /* Validity Constraint: Enumeration */
4562 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4563 xmlEnumerationPtr tree = attrDecl->tree;
4564 while (tree != NULL) {
4565 if (xmlStrEqual(tree->name, value)) break;
4566 tree = tree->next;
4567 }
4568 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004569 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004570 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004571"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4572 value, ns->prefix, elem->name);
4573 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004574 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004575"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004576 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004577 }
4578 ret = 0;
4579 }
4580 }
4581
4582 /* Fixed Attribute Default */
4583 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4584 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004585 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004586 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004587 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4588 ns->prefix, elem->name, attrDecl->defaultValue);
4589 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004590 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004591 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004592 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004593 }
4594 ret = 0;
4595 }
4596
4597 /* Extra check for the attribute value */
4598 if (ns->prefix != NULL) {
4599 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4600 attrDecl->atype, value);
4601 } else {
4602 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4603 attrDecl->atype, value);
4604 }
4605
4606 return(ret);
4607}
4608
Daniel Veillard118aed72002-09-24 14:13:13 +00004609#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004610/**
4611 * xmlValidateSkipIgnorable:
4612 * @ctxt: the validation context
4613 * @child: the child list
4614 *
4615 * Skip ignorable elements w.r.t. the validation process
4616 *
4617 * returns the first element to consider for validation of the content model
4618 */
4619
4620static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004621xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004622 while (child != NULL) {
4623 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004624 /* These things are ignored (skipped) during validation. */
4625 case XML_PI_NODE:
4626 case XML_COMMENT_NODE:
4627 case XML_XINCLUDE_START:
4628 case XML_XINCLUDE_END:
4629 child = child->next;
4630 break;
4631 case XML_TEXT_NODE:
4632 if (xmlIsBlankNode(child))
4633 child = child->next;
4634 else
4635 return(child);
4636 break;
4637 /* keep current node */
4638 default:
4639 return(child);
4640 }
4641 }
4642 return(child);
4643}
4644
4645/**
4646 * xmlValidateElementType:
4647 * @ctxt: the validation context
4648 *
4649 * Try to validate the content model of an element internal function
4650 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004651 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4652 * reference is found and -3 if the validation succeeded but
4653 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004654 */
4655
4656static int
4657xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004658 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004659 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004660
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004661 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004662 if ((NODE == NULL) && (CONT == NULL))
4663 return(1);
4664 if ((NODE == NULL) &&
4665 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4666 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4667 return(1);
4668 }
4669 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004670 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004671 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004672
4673 /*
4674 * We arrive here when more states need to be examined
4675 */
4676cont:
4677
4678 /*
4679 * We just recovered from a rollback generated by a possible
4680 * epsilon transition, go directly to the analysis phase
4681 */
4682 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004683 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004684 DEBUG_VALID_STATE(NODE, CONT)
4685 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004686 goto analyze;
4687 }
4688
4689 DEBUG_VALID_STATE(NODE, CONT)
4690 /*
4691 * we may have to save a backup state here. This is the equivalent
4692 * of handling epsilon transition in NFAs.
4693 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004694 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004695 ((CONT->parent == NULL) ||
4696 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004697 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004698 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004699 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004700 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004701 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4702 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004703 }
4704
4705
4706 /*
4707 * Check first if the content matches
4708 */
4709 switch (CONT->type) {
4710 case XML_ELEMENT_CONTENT_PCDATA:
4711 if (NODE == NULL) {
4712 DEBUG_VALID_MSG("pcdata failed no node");
4713 ret = 0;
4714 break;
4715 }
4716 if (NODE->type == XML_TEXT_NODE) {
4717 DEBUG_VALID_MSG("pcdata found, skip to next");
4718 /*
4719 * go to next element in the content model
4720 * skipping ignorable elems
4721 */
4722 do {
4723 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004724 NODE = xmlValidateSkipIgnorable(NODE);
4725 if ((NODE != NULL) &&
4726 (NODE->type == XML_ENTITY_REF_NODE))
4727 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004728 } while ((NODE != NULL) &&
4729 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004730 (NODE->type != XML_TEXT_NODE) &&
4731 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004732 ret = 1;
4733 break;
4734 } else {
4735 DEBUG_VALID_MSG("pcdata failed");
4736 ret = 0;
4737 break;
4738 }
4739 break;
4740 case XML_ELEMENT_CONTENT_ELEMENT:
4741 if (NODE == NULL) {
4742 DEBUG_VALID_MSG("element failed no node");
4743 ret = 0;
4744 break;
4745 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004746 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4747 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004748 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004749 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4750 ret = (CONT->prefix == NULL);
4751 } else if (CONT->prefix == NULL) {
4752 ret = 0;
4753 } else {
4754 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4755 }
4756 }
4757 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004758 DEBUG_VALID_MSG("element found, skip to next");
4759 /*
4760 * go to next element in the content model
4761 * skipping ignorable elems
4762 */
4763 do {
4764 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004765 NODE = xmlValidateSkipIgnorable(NODE);
4766 if ((NODE != NULL) &&
4767 (NODE->type == XML_ENTITY_REF_NODE))
4768 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004769 } while ((NODE != NULL) &&
4770 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004771 (NODE->type != XML_TEXT_NODE) &&
4772 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004773 } else {
4774 DEBUG_VALID_MSG("element failed");
4775 ret = 0;
4776 break;
4777 }
4778 break;
4779 case XML_ELEMENT_CONTENT_OR:
4780 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004781 * Small optimization.
4782 */
4783 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4784 if ((NODE == NULL) ||
4785 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4786 DEPTH++;
4787 CONT = CONT->c2;
4788 goto cont;
4789 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004790 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4791 ret = (CONT->c1->prefix == NULL);
4792 } else if (CONT->c1->prefix == NULL) {
4793 ret = 0;
4794 } else {
4795 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4796 }
4797 if (ret == 0) {
4798 DEPTH++;
4799 CONT = CONT->c2;
4800 goto cont;
4801 }
Daniel Veillard85349052001-04-20 13:48:21 +00004802 }
4803
4804 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004805 * save the second branch 'or' branch
4806 */
4807 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004808 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4809 OCCURS, ROLLBACK_OR) < 0)
4810 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004811 DEPTH++;
4812 CONT = CONT->c1;
4813 goto cont;
4814 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004815 /*
4816 * Small optimization.
4817 */
4818 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4819 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4820 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4821 if ((NODE == NULL) ||
4822 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4823 DEPTH++;
4824 CONT = CONT->c2;
4825 goto cont;
4826 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004827 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4828 ret = (CONT->c1->prefix == NULL);
4829 } else if (CONT->c1->prefix == NULL) {
4830 ret = 0;
4831 } else {
4832 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4833 }
4834 if (ret == 0) {
4835 DEPTH++;
4836 CONT = CONT->c2;
4837 goto cont;
4838 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004839 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004840 DEPTH++;
4841 CONT = CONT->c1;
4842 goto cont;
4843 }
4844
4845 /*
4846 * At this point handle going up in the tree
4847 */
4848 if (ret == -1) {
4849 DEBUG_VALID_MSG("error found returning");
4850 return(ret);
4851 }
4852analyze:
4853 while (CONT != NULL) {
4854 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004855 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004856 * this level.
4857 */
4858 if (ret == 0) {
4859 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004860 xmlNodePtr cur;
4861
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004862 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004863 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004864 DEBUG_VALID_MSG("Once branch failed, rollback");
4865 if (vstateVPop(ctxt) < 0 ) {
4866 DEBUG_VALID_MSG("exhaustion, failed");
4867 return(0);
4868 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004869 if (cur != ctxt->vstate->node)
4870 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004871 goto cont;
4872 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004873 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004874 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004875 DEBUG_VALID_MSG("Plus branch failed, rollback");
4876 if (vstateVPop(ctxt) < 0 ) {
4877 DEBUG_VALID_MSG("exhaustion, failed");
4878 return(0);
4879 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004880 if (cur != ctxt->vstate->node)
4881 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004882 goto cont;
4883 }
4884 DEBUG_VALID_MSG("Plus branch found");
4885 ret = 1;
4886 break;
4887 case XML_ELEMENT_CONTENT_MULT:
4888#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004889 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004890 DEBUG_VALID_MSG("Mult branch failed");
4891 } else {
4892 DEBUG_VALID_MSG("Mult branch found");
4893 }
4894#endif
4895 ret = 1;
4896 break;
4897 case XML_ELEMENT_CONTENT_OPT:
4898 DEBUG_VALID_MSG("Option branch failed");
4899 ret = 1;
4900 break;
4901 }
4902 } else {
4903 switch (CONT->ocur) {
4904 case XML_ELEMENT_CONTENT_OPT:
4905 DEBUG_VALID_MSG("Option branch succeeded");
4906 ret = 1;
4907 break;
4908 case XML_ELEMENT_CONTENT_ONCE:
4909 DEBUG_VALID_MSG("Once branch succeeded");
4910 ret = 1;
4911 break;
4912 case XML_ELEMENT_CONTENT_PLUS:
4913 if (STATE == ROLLBACK_PARENT) {
4914 DEBUG_VALID_MSG("Plus branch rollback");
4915 ret = 1;
4916 break;
4917 }
4918 if (NODE == NULL) {
4919 DEBUG_VALID_MSG("Plus branch exhausted");
4920 ret = 1;
4921 break;
4922 }
4923 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004924 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004925 goto cont;
4926 case XML_ELEMENT_CONTENT_MULT:
4927 if (STATE == ROLLBACK_PARENT) {
4928 DEBUG_VALID_MSG("Mult branch rollback");
4929 ret = 1;
4930 break;
4931 }
4932 if (NODE == NULL) {
4933 DEBUG_VALID_MSG("Mult branch exhausted");
4934 ret = 1;
4935 break;
4936 }
4937 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004938 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004939 goto cont;
4940 }
4941 }
4942 STATE = 0;
4943
4944 /*
4945 * Then act accordingly at the parent level
4946 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004947 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004948 if (CONT->parent == NULL)
4949 break;
4950
4951 switch (CONT->parent->type) {
4952 case XML_ELEMENT_CONTENT_PCDATA:
4953 DEBUG_VALID_MSG("Error: parent pcdata");
4954 return(-1);
4955 case XML_ELEMENT_CONTENT_ELEMENT:
4956 DEBUG_VALID_MSG("Error: parent element");
4957 return(-1);
4958 case XML_ELEMENT_CONTENT_OR:
4959 if (ret == 1) {
4960 DEBUG_VALID_MSG("Or succeeded");
4961 CONT = CONT->parent;
4962 DEPTH--;
4963 } else {
4964 DEBUG_VALID_MSG("Or failed");
4965 CONT = CONT->parent;
4966 DEPTH--;
4967 }
4968 break;
4969 case XML_ELEMENT_CONTENT_SEQ:
4970 if (ret == 0) {
4971 DEBUG_VALID_MSG("Sequence failed");
4972 CONT = CONT->parent;
4973 DEPTH--;
4974 } else if (CONT == CONT->parent->c1) {
4975 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4976 CONT = CONT->parent->c2;
4977 goto cont;
4978 } else {
4979 DEBUG_VALID_MSG("Sequence succeeded");
4980 CONT = CONT->parent;
4981 DEPTH--;
4982 }
4983 }
4984 }
4985 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004986 xmlNodePtr cur;
4987
4988 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004989 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4990 if (vstateVPop(ctxt) < 0 ) {
4991 DEBUG_VALID_MSG("exhaustion, failed");
4992 return(0);
4993 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004994 if (cur != ctxt->vstate->node)
4995 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004996 goto cont;
4997 }
4998 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004999 xmlNodePtr cur;
5000
5001 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005002 DEBUG_VALID_MSG("Failure, rollback");
5003 if (vstateVPop(ctxt) < 0 ) {
5004 DEBUG_VALID_MSG("exhaustion, failed");
5005 return(0);
5006 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005007 if (cur != ctxt->vstate->node)
5008 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005009 goto cont;
5010 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005011 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005012}
Daniel Veillard23e73572002-09-19 19:56:43 +00005013#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005014
5015/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00005016 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005017 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00005018 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005019 * @content: An element
5020 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5021 *
5022 * This will dump the list of elements to the buffer
5023 * Intended just for the debug routine
5024 */
5025static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00005026xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005027 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00005028 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005029
5030 if (node == NULL) return;
5031 if (glob) strcat(buf, "(");
5032 cur = node;
5033 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005034 len = strlen(buf);
5035 if (size - len < 50) {
5036 if ((size - len > 4) && (buf[len - 1] != '.'))
5037 strcat(buf, " ...");
5038 return;
5039 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005040 switch (cur->type) {
5041 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005042 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005043 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005044 if ((size - len > 4) && (buf[len - 1] != '.'))
5045 strcat(buf, " ...");
5046 return;
5047 }
5048 strcat(buf, (char *) cur->ns->prefix);
5049 strcat(buf, ":");
5050 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005051 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005052 if ((size - len > 4) && (buf[len - 1] != '.'))
5053 strcat(buf, " ...");
5054 return;
5055 }
5056 strcat(buf, (char *) cur->name);
5057 if (cur->next != NULL)
5058 strcat(buf, " ");
5059 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005060 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005061 if (xmlIsBlankNode(cur))
5062 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005063 case XML_CDATA_SECTION_NODE:
5064 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005065 strcat(buf, "CDATA");
5066 if (cur->next != NULL)
5067 strcat(buf, " ");
5068 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005069 case XML_ATTRIBUTE_NODE:
5070 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005071#ifdef LIBXML_DOCB_ENABLED
5072 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005073#endif
5074 case XML_HTML_DOCUMENT_NODE:
5075 case XML_DOCUMENT_TYPE_NODE:
5076 case XML_DOCUMENT_FRAG_NODE:
5077 case XML_NOTATION_NODE:
5078 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005079 strcat(buf, "???");
5080 if (cur->next != NULL)
5081 strcat(buf, " ");
5082 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005083 case XML_ENTITY_NODE:
5084 case XML_PI_NODE:
5085 case XML_DTD_NODE:
5086 case XML_COMMENT_NODE:
5087 case XML_ELEMENT_DECL:
5088 case XML_ATTRIBUTE_DECL:
5089 case XML_ENTITY_DECL:
5090 case XML_XINCLUDE_START:
5091 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005092 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005093 }
5094 cur = cur->next;
5095 }
5096 if (glob) strcat(buf, ")");
5097}
5098
5099/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005100 * xmlValidateElementContent:
5101 * @ctxt: the validation context
5102 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005103 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005104 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005105 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005106 *
5107 * Try to validate the content model of an element
5108 *
5109 * returns 1 if valid or 0 if not and -1 in case of error
5110 */
5111
5112static int
5113xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005114 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00005115 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00005116#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00005117 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00005118#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00005119 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005120 xmlElementContentPtr cont;
5121 const xmlChar *name;
5122
5123 if (elemDecl == NULL)
5124 return(-1);
5125 cont = elemDecl->content;
5126 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005127
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005128#ifdef LIBXML_REGEXP_ENABLED
5129 /* Build the regexp associated to the content model */
5130 if (elemDecl->contModel == NULL)
5131 ret = xmlValidBuildContentModel(ctxt, elemDecl);
5132 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005133 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005134 } else {
5135 xmlRegExecCtxtPtr exec;
5136
Daniel Veillardec498e12003-02-05 11:01:50 +00005137 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5138 return(-1);
5139 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005140 ctxt->nodeMax = 0;
5141 ctxt->nodeNr = 0;
5142 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005143 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5144 if (exec != NULL) {
5145 cur = child;
5146 while (cur != NULL) {
5147 switch (cur->type) {
5148 case XML_ENTITY_REF_NODE:
5149 /*
5150 * Push the current node to be able to roll back
5151 * and process within the entity
5152 */
5153 if ((cur->children != NULL) &&
5154 (cur->children->children != NULL)) {
5155 nodeVPush(ctxt, cur);
5156 cur = cur->children->children;
5157 continue;
5158 }
5159 break;
5160 case XML_TEXT_NODE:
5161 if (xmlIsBlankNode(cur))
5162 break;
5163 ret = 0;
5164 goto fail;
5165 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00005166 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005167 ret = 0;
5168 goto fail;
5169 case XML_ELEMENT_NODE:
5170 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005171 xmlChar fn[50];
5172 xmlChar *fullname;
5173
5174 fullname = xmlBuildQName(cur->name,
5175 cur->ns->prefix, fn, 50);
5176 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005177 ret = -1;
5178 goto fail;
5179 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005180 ret = xmlRegExecPushString(exec, fullname, NULL);
5181 if ((fullname != fn) && (fullname != cur->name))
5182 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005183 } else {
5184 ret = xmlRegExecPushString(exec, cur->name, NULL);
5185 }
5186 break;
5187 default:
5188 break;
5189 }
5190 /*
5191 * Switch to next element
5192 */
5193 cur = cur->next;
5194 while (cur == NULL) {
5195 cur = nodeVPop(ctxt);
5196 if (cur == NULL)
5197 break;
5198 cur = cur->next;
5199 }
5200 }
5201 ret = xmlRegExecPushString(exec, NULL, NULL);
5202fail:
5203 xmlRegFreeExecCtxt(exec);
5204 }
5205 }
5206#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005207 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005208 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005209 */
5210 ctxt->vstateMax = 8;
5211 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5212 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5213 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005214 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005215 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005216 }
5217 /*
5218 * The first entry in the stack is reserved to the current state
5219 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005220 ctxt->nodeMax = 0;
5221 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005222 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005223 ctxt->vstate = &ctxt->vstateTab[0];
5224 ctxt->vstateNr = 1;
5225 CONT = cont;
5226 NODE = child;
5227 DEPTH = 0;
5228 OCCURS = 0;
5229 STATE = 0;
5230 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005231 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005232 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5233 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005234 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005235 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005236 /*
5237 * An entities reference appeared at this level.
5238 * Buid a minimal representation of this node content
5239 * sufficient to run the validation process on it
5240 */
5241 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005242 cur = child;
5243 while (cur != NULL) {
5244 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005245 case XML_ENTITY_REF_NODE:
5246 /*
5247 * Push the current node to be able to roll back
5248 * and process within the entity
5249 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005250 if ((cur->children != NULL) &&
5251 (cur->children->children != NULL)) {
5252 nodeVPush(ctxt, cur);
5253 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005254 continue;
5255 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005256 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005257 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005258 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005259 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005260 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005261 case XML_CDATA_SECTION_NODE:
5262 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005263 case XML_ELEMENT_NODE:
5264 /*
5265 * Allocate a new node and minimally fills in
5266 * what's required
5267 */
5268 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5269 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005270 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005271 xmlFreeNodeList(repl);
5272 ret = -1;
5273 goto done;
5274 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005275 tmp->type = cur->type;
5276 tmp->name = cur->name;
5277 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005278 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005279 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005280 if (repl == NULL)
5281 repl = last = tmp;
5282 else {
5283 last->next = tmp;
5284 last = tmp;
5285 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005286 if (cur->type == XML_CDATA_SECTION_NODE) {
5287 /*
5288 * E59 spaces in CDATA does not match the
5289 * nonterminal S
5290 */
5291 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5292 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005293 break;
5294 default:
5295 break;
5296 }
5297 /*
5298 * Switch to next element
5299 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005300 cur = cur->next;
5301 while (cur == NULL) {
5302 cur = nodeVPop(ctxt);
5303 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005304 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005305 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005306 }
5307 }
5308
5309 /*
5310 * Relaunch the validation
5311 */
5312 ctxt->vstate = &ctxt->vstateTab[0];
5313 ctxt->vstateNr = 1;
5314 CONT = cont;
5315 NODE = repl;
5316 DEPTH = 0;
5317 OCCURS = 0;
5318 STATE = 0;
5319 ret = xmlValidateElementType(ctxt);
5320 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005321#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005322 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005323 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5324 char expr[5000];
5325 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005326
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005327 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005328 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005329 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005330#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005331 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005332 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005333 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005334#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005335 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005336
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005337 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005338 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5339 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5340 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005341 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005342 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5343 "Element content does not follow the DTD, expecting %s, got %s\n",
5344 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005345 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005346 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005347 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005348 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005349 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005350 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005351 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005352 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5353 "Element content does not follow the DTD\n",
5354 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005355 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005356 }
5357 ret = 0;
5358 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005359 if (ret == -3)
5360 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005361
Daniel Veillard23e73572002-09-19 19:56:43 +00005362#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005363done:
5364 /*
5365 * Deallocate the copy if done, and free up the validation stack
5366 */
5367 while (repl != NULL) {
5368 tmp = repl->next;
5369 xmlFree(repl);
5370 repl = tmp;
5371 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005372 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005373 if (ctxt->vstateTab != NULL) {
5374 xmlFree(ctxt->vstateTab);
5375 ctxt->vstateTab = NULL;
5376 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005377#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005378 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005379 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005380 if (ctxt->nodeTab != NULL) {
5381 xmlFree(ctxt->nodeTab);
5382 ctxt->nodeTab = NULL;
5383 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005384 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005385
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005386}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005387
Owen Taylor3473f882001-02-23 17:55:21 +00005388/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005389 * xmlValidateCdataElement:
5390 * @ctxt: the validation context
5391 * @doc: a document instance
5392 * @elem: an element instance
5393 *
5394 * Check that an element follows #CDATA
5395 *
5396 * returns 1 if valid or 0 otherwise
5397 */
5398static int
5399xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5400 xmlNodePtr elem) {
5401 int ret = 1;
5402 xmlNodePtr cur, child;
5403
Daniel Veillardceb09b92002-10-04 11:46:37 +00005404 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005405 return(0);
5406
5407 child = elem->children;
5408
5409 cur = child;
5410 while (cur != NULL) {
5411 switch (cur->type) {
5412 case XML_ENTITY_REF_NODE:
5413 /*
5414 * Push the current node to be able to roll back
5415 * and process within the entity
5416 */
5417 if ((cur->children != NULL) &&
5418 (cur->children->children != NULL)) {
5419 nodeVPush(ctxt, cur);
5420 cur = cur->children->children;
5421 continue;
5422 }
5423 break;
5424 case XML_COMMENT_NODE:
5425 case XML_PI_NODE:
5426 case XML_TEXT_NODE:
5427 case XML_CDATA_SECTION_NODE:
5428 break;
5429 default:
5430 ret = 0;
5431 goto done;
5432 }
5433 /*
5434 * Switch to next element
5435 */
5436 cur = cur->next;
5437 while (cur == NULL) {
5438 cur = nodeVPop(ctxt);
5439 if (cur == NULL)
5440 break;
5441 cur = cur->next;
5442 }
5443 }
5444done:
5445 ctxt->nodeMax = 0;
5446 ctxt->nodeNr = 0;
5447 if (ctxt->nodeTab != NULL) {
5448 xmlFree(ctxt->nodeTab);
5449 ctxt->nodeTab = NULL;
5450 }
5451 return(ret);
5452}
5453
5454/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005455 * xmlValidateCheckMixed:
5456 * @ctxt: the validation context
5457 * @cont: the mixed content model
5458 * @qname: the qualified name as appearing in the serialization
5459 *
5460 * Check if the given node is part of the content model.
5461 *
5462 * Returns 1 if yes, 0 if no, -1 in case of error
5463 */
5464static int
William M. Brackedb65a72004-02-06 07:36:04 +00005465xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005466 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005467 const xmlChar *name;
5468 int plen;
5469 name = xmlSplitQName3(qname, &plen);
5470
5471 if (name == NULL) {
5472 while (cont != NULL) {
5473 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5474 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5475 return(1);
5476 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5477 (cont->c1 != NULL) &&
5478 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5479 if ((cont->c1->prefix == NULL) &&
5480 (xmlStrEqual(cont->c1->name, qname)))
5481 return(1);
5482 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5483 (cont->c1 == NULL) ||
5484 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005485 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5486 "Internal: MIXED struct corrupted\n",
5487 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005488 break;
5489 }
5490 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005491 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005492 } else {
5493 while (cont != NULL) {
5494 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5495 if ((cont->prefix != NULL) &&
5496 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5497 (xmlStrEqual(cont->name, name)))
5498 return(1);
5499 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5500 (cont->c1 != NULL) &&
5501 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5502 if ((cont->c1->prefix != NULL) &&
5503 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5504 (xmlStrEqual(cont->c1->name, name)))
5505 return(1);
5506 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5507 (cont->c1 == NULL) ||
5508 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005509 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5510 "Internal: MIXED struct corrupted\n",
5511 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005512 break;
5513 }
5514 cont = cont->c2;
5515 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005516 }
5517 return(0);
5518}
5519
5520/**
5521 * xmlValidGetElemDecl:
5522 * @ctxt: the validation context
5523 * @doc: a document instance
5524 * @elem: an element instance
5525 * @extsubset: pointer, (out) indicate if the declaration was found
5526 * in the external subset.
5527 *
5528 * Finds a declaration associated to an element in the document.
5529 *
5530 * returns the pointer to the declaration or NULL if not found.
5531 */
5532static xmlElementPtr
5533xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5534 xmlNodePtr elem, int *extsubset) {
5535 xmlElementPtr elemDecl = NULL;
5536 const xmlChar *prefix = NULL;
5537
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005538 if ((ctxt == NULL) || (doc == NULL) ||
5539 (elem == NULL) || (elem->name == NULL))
5540 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005541 if (extsubset != NULL)
5542 *extsubset = 0;
5543
5544 /*
5545 * Fetch the declaration for the qualified name
5546 */
5547 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5548 prefix = elem->ns->prefix;
5549
5550 if (prefix != NULL) {
5551 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5552 elem->name, prefix);
5553 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5554 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5555 elem->name, prefix);
5556 if ((elemDecl != NULL) && (extsubset != NULL))
5557 *extsubset = 1;
5558 }
5559 }
5560
5561 /*
5562 * Fetch the declaration for the non qualified name
5563 * This is "non-strict" validation should be done on the
5564 * full QName but in that case being flexible makes sense.
5565 */
5566 if (elemDecl == NULL) {
5567 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5568 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5569 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5570 if ((elemDecl != NULL) && (extsubset != NULL))
5571 *extsubset = 1;
5572 }
5573 }
5574 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005575 xmlErrValidNode(ctxt, elem,
5576 XML_DTD_UNKNOWN_ELEM,
5577 "No declaration for element %s\n",
5578 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005579 }
5580 return(elemDecl);
5581}
5582
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005583#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005584/**
5585 * xmlValidatePushElement:
5586 * @ctxt: the validation context
5587 * @doc: a document instance
5588 * @elem: an element instance
5589 * @qname: the qualified name as appearing in the serialization
5590 *
5591 * Push a new element start on the validation stack.
5592 *
5593 * returns 1 if no validation problem was found or 0 otherwise
5594 */
5595int
5596xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5597 xmlNodePtr elem, const xmlChar *qname) {
5598 int ret = 1;
5599 xmlElementPtr eDecl;
5600 int extsubset = 0;
5601
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005602 if (ctxt == NULL)
5603 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005604/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005605 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5606 xmlValidStatePtr state = ctxt->vstate;
5607 xmlElementPtr elemDecl;
5608
5609 /*
5610 * Check the new element agaisnt the content model of the new elem.
5611 */
5612 if (state->elemDecl != NULL) {
5613 elemDecl = state->elemDecl;
5614
5615 switch(elemDecl->etype) {
5616 case XML_ELEMENT_TYPE_UNDEFINED:
5617 ret = 0;
5618 break;
5619 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005620 xmlErrValidNode(ctxt, state->node,
5621 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005622 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005623 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005624 ret = 0;
5625 break;
5626 case XML_ELEMENT_TYPE_ANY:
5627 /* I don't think anything is required then */
5628 break;
5629 case XML_ELEMENT_TYPE_MIXED:
5630 /* simple case of declared as #PCDATA */
5631 if ((elemDecl->content != NULL) &&
5632 (elemDecl->content->type ==
5633 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005634 xmlErrValidNode(ctxt, state->node,
5635 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005636 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005637 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005638 ret = 0;
5639 } else {
5640 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5641 qname);
5642 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005643 xmlErrValidNode(ctxt, state->node,
5644 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005645 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005646 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005647 }
5648 }
5649 break;
5650 case XML_ELEMENT_TYPE_ELEMENT:
5651 /*
5652 * TODO:
5653 * VC: Standalone Document Declaration
5654 * - element types with element content, if white space
5655 * occurs directly within any instance of those types.
5656 */
5657 if (state->exec != NULL) {
5658 ret = xmlRegExecPushString(state->exec, qname, NULL);
5659 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005660 xmlErrValidNode(ctxt, state->node,
5661 XML_DTD_CONTENT_MODEL,
5662 "Element %s content does not follow the DTD, Misplaced %s\n",
5663 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005664 ret = 0;
5665 } else {
5666 ret = 1;
5667 }
5668 }
5669 break;
5670 }
5671 }
5672 }
5673 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5674 vstateVPush(ctxt, eDecl, elem);
5675 return(ret);
5676}
5677
5678/**
5679 * xmlValidatePushCData:
5680 * @ctxt: the validation context
5681 * @data: some character data read
5682 * @len: the lenght of the data
5683 *
5684 * check the CData parsed for validation in the current stack
5685 *
5686 * returns 1 if no validation problem was found or 0 otherwise
5687 */
5688int
5689xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5690 int ret = 1;
5691
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005692/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005693 if (ctxt == NULL)
5694 return(0);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005695 if (len <= 0)
5696 return(ret);
5697 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5698 xmlValidStatePtr state = ctxt->vstate;
5699 xmlElementPtr elemDecl;
5700
5701 /*
5702 * Check the new element agaisnt the content model of the new elem.
5703 */
5704 if (state->elemDecl != NULL) {
5705 elemDecl = state->elemDecl;
5706
5707 switch(elemDecl->etype) {
5708 case XML_ELEMENT_TYPE_UNDEFINED:
5709 ret = 0;
5710 break;
5711 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005712 xmlErrValidNode(ctxt, state->node,
5713 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005714 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005715 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005716 ret = 0;
5717 break;
5718 case XML_ELEMENT_TYPE_ANY:
5719 break;
5720 case XML_ELEMENT_TYPE_MIXED:
5721 break;
5722 case XML_ELEMENT_TYPE_ELEMENT:
5723 if (len > 0) {
5724 int i;
5725
5726 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005727 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005728 xmlErrValidNode(ctxt, state->node,
5729 XML_DTD_CONTENT_MODEL,
5730 "Element %s content does not follow the DTD, Text not allowed\n",
5731 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005732 ret = 0;
5733 goto done;
5734 }
5735 }
5736 /*
5737 * TODO:
5738 * VC: Standalone Document Declaration
5739 * element types with element content, if white space
5740 * occurs directly within any instance of those types.
5741 */
5742 }
5743 break;
5744 }
5745 }
5746 }
5747done:
5748 return(ret);
5749}
5750
5751/**
5752 * xmlValidatePopElement:
5753 * @ctxt: the validation context
5754 * @doc: a document instance
5755 * @elem: an element instance
5756 * @qname: the qualified name as appearing in the serialization
5757 *
5758 * Pop the element end from the validation stack.
5759 *
5760 * returns 1 if no validation problem was found or 0 otherwise
5761 */
5762int
5763xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005764 xmlNodePtr elem ATTRIBUTE_UNUSED,
5765 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005766 int ret = 1;
5767
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005768 if (ctxt == NULL)
5769 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005770/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005771 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5772 xmlValidStatePtr state = ctxt->vstate;
5773 xmlElementPtr elemDecl;
5774
5775 /*
5776 * Check the new element agaisnt the content model of the new elem.
5777 */
5778 if (state->elemDecl != NULL) {
5779 elemDecl = state->elemDecl;
5780
5781 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5782 if (state->exec != NULL) {
5783 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5784 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005785 xmlErrValidNode(ctxt, state->node,
5786 XML_DTD_CONTENT_MODEL,
5787 "Element %s content does not follow the DTD, Expecting more child\n",
5788 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005789 } else {
5790 /*
5791 * previous validation errors should not generate
5792 * a new one here
5793 */
5794 ret = 1;
5795 }
5796 }
5797 }
5798 }
5799 vstateVPop(ctxt);
5800 }
5801 return(ret);
5802}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005803#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005804
5805/**
Owen Taylor3473f882001-02-23 17:55:21 +00005806 * xmlValidateOneElement:
5807 * @ctxt: the validation context
5808 * @doc: a document instance
5809 * @elem: an element instance
5810 *
5811 * Try to validate a single element and it's attributes,
5812 * basically it does the following checks as described by the
5813 * XML-1.0 recommendation:
5814 * - [ VC: Element Valid ]
5815 * - [ VC: Required Attribute ]
5816 * Then call xmlValidateOneAttribute() for each attribute present.
5817 *
5818 * The ID/IDREF checkings are done separately
5819 *
5820 * returns 1 if valid or 0 otherwise
5821 */
5822
5823int
5824xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5825 xmlNodePtr elem) {
5826 xmlElementPtr elemDecl = NULL;
5827 xmlElementContentPtr cont;
5828 xmlAttributePtr attr;
5829 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005830 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005831 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005832 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005833
5834 CHECK_DTD;
5835
5836 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005837 switch (elem->type) {
5838 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005839 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5840 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005841 return(0);
5842 case XML_TEXT_NODE:
5843 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005844 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5845 "Text element has children !\n",
5846 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005847 return(0);
5848 }
5849 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005850 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5851 "Text element has attribute !\n",
5852 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005853 return(0);
5854 }
5855 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005856 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5857 "Text element has namespace !\n",
5858 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005859 return(0);
5860 }
5861 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005862 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5863 "Text element has namespace !\n",
5864 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005865 return(0);
5866 }
5867 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005868 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5869 "Text element has no content !\n",
5870 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005871 return(0);
5872 }
5873 return(1);
5874 case XML_XINCLUDE_START:
5875 case XML_XINCLUDE_END:
5876 return(1);
5877 case XML_CDATA_SECTION_NODE:
5878 case XML_ENTITY_REF_NODE:
5879 case XML_PI_NODE:
5880 case XML_COMMENT_NODE:
5881 return(1);
5882 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005883 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5884 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005885 return(0);
5886 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005887 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5888 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005889 return(0);
5890 case XML_DOCUMENT_NODE:
5891 case XML_DOCUMENT_TYPE_NODE:
5892 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005893 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5894 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005895 return(0);
5896 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005897 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5898 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005899 return(0);
5900 case XML_ELEMENT_NODE:
5901 break;
5902 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005903 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5904 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005905 return(0);
5906 }
Owen Taylor3473f882001-02-23 17:55:21 +00005907
5908 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005909 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005910 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005911 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5912 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005913 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005914
Daniel Veillardea7751d2002-12-20 00:16:24 +00005915 /*
5916 * If vstateNr is not zero that means continuous validation is
5917 * activated, do not try to check the content model at that level.
5918 */
5919 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005920 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005921 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005922 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005923 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5924 "No declaration for element %s\n",
5925 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005926 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005927 case XML_ELEMENT_TYPE_EMPTY:
5928 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005929 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005930 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005931 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005932 ret = 0;
5933 }
5934 break;
5935 case XML_ELEMENT_TYPE_ANY:
5936 /* I don't think anything is required then */
5937 break;
5938 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005939
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005940 /* simple case of declared as #PCDATA */
5941 if ((elemDecl->content != NULL) &&
5942 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5943 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5944 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005945 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005946 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005947 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005948 }
5949 break;
5950 }
Owen Taylor3473f882001-02-23 17:55:21 +00005951 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005952 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005953 while (child != NULL) {
5954 if (child->type == XML_ELEMENT_NODE) {
5955 name = child->name;
5956 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005957 xmlChar fn[50];
5958 xmlChar *fullname;
5959
5960 fullname = xmlBuildQName(child->name, child->ns->prefix,
5961 fn, 50);
5962 if (fullname == NULL)
5963 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005964 cont = elemDecl->content;
5965 while (cont != NULL) {
5966 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005967 if (xmlStrEqual(cont->name, fullname))
5968 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005969 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5970 (cont->c1 != NULL) &&
5971 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005972 if (xmlStrEqual(cont->c1->name, fullname))
5973 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005974 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5975 (cont->c1 == NULL) ||
5976 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005977 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5978 "Internal: MIXED struct corrupted\n",
5979 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005980 break;
5981 }
5982 cont = cont->c2;
5983 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005984 if ((fullname != fn) && (fullname != child->name))
5985 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005986 if (cont != NULL)
5987 goto child_ok;
5988 }
5989 cont = elemDecl->content;
5990 while (cont != NULL) {
5991 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5992 if (xmlStrEqual(cont->name, name)) break;
5993 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5994 (cont->c1 != NULL) &&
5995 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5996 if (xmlStrEqual(cont->c1->name, name)) break;
5997 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5998 (cont->c1 == NULL) ||
5999 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006000 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
6001 "Internal: MIXED struct corrupted\n",
6002 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006003 break;
6004 }
6005 cont = cont->c2;
6006 }
6007 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006008 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006009 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006010 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006011 ret = 0;
6012 }
6013 }
6014child_ok:
6015 child = child->next;
6016 }
6017 break;
6018 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006019 if ((doc->standalone == 1) && (extsubset == 1)) {
6020 /*
6021 * VC: Standalone Document Declaration
6022 * - element types with element content, if white space
6023 * occurs directly within any instance of those types.
6024 */
6025 child = elem->children;
6026 while (child != NULL) {
6027 if (child->type == XML_TEXT_NODE) {
6028 const xmlChar *content = child->content;
6029
William M. Brack76e95df2003-10-18 16:20:14 +00006030 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006031 content++;
6032 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006033 xmlErrValidNode(ctxt, elem,
6034 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006035"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006036 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006037 ret = 0;
6038 break;
6039 }
6040 }
6041 child =child->next;
6042 }
6043 }
Owen Taylor3473f882001-02-23 17:55:21 +00006044 child = elem->children;
6045 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00006046 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006047 if (tmp <= 0)
6048 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006049 break;
6050 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00006051 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00006052
6053 /* [ VC: Required Attribute ] */
6054 attr = elemDecl->attributes;
6055 while (attr != NULL) {
6056 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006057 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006058
Daniel Veillarde4301c82002-02-13 13:32:35 +00006059 if ((attr->prefix == NULL) &&
6060 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6061 xmlNsPtr ns;
6062
6063 ns = elem->nsDef;
6064 while (ns != NULL) {
6065 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006066 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006067 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006068 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006069 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6070 xmlNsPtr ns;
6071
6072 ns = elem->nsDef;
6073 while (ns != NULL) {
6074 if (xmlStrEqual(attr->name, ns->prefix))
6075 goto found;
6076 ns = ns->next;
6077 }
6078 } else {
6079 xmlAttrPtr attrib;
6080
6081 attrib = elem->properties;
6082 while (attrib != NULL) {
6083 if (xmlStrEqual(attrib->name, attr->name)) {
6084 if (attr->prefix != NULL) {
6085 xmlNsPtr nameSpace = attrib->ns;
6086
6087 if (nameSpace == NULL)
6088 nameSpace = elem->ns;
6089 /*
6090 * qualified names handling is problematic, having a
6091 * different prefix should be possible but DTDs don't
6092 * allow to define the URI instead of the prefix :-(
6093 */
6094 if (nameSpace == NULL) {
6095 if (qualified < 0)
6096 qualified = 0;
6097 } else if (!xmlStrEqual(nameSpace->prefix,
6098 attr->prefix)) {
6099 if (qualified < 1)
6100 qualified = 1;
6101 } else
6102 goto found;
6103 } else {
6104 /*
6105 * We should allow applications to define namespaces
6106 * for their application even if the DTD doesn't
6107 * carry one, otherwise, basically we would always
6108 * break.
6109 */
6110 goto found;
6111 }
6112 }
6113 attrib = attrib->next;
6114 }
Owen Taylor3473f882001-02-23 17:55:21 +00006115 }
6116 if (qualified == -1) {
6117 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006118 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006119 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006120 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006121 ret = 0;
6122 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006123 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006124 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00006125 elem->name, attr->prefix,attr->name);
6126 ret = 0;
6127 }
6128 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006129 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006130 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006131 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006132 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006133 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006134 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006135 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006136 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006137 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
6138 /*
6139 * Special tests checking #FIXED namespace declarations
6140 * have the right value since this is not done as an
6141 * attribute checking
6142 */
6143 if ((attr->prefix == NULL) &&
6144 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6145 xmlNsPtr ns;
6146
6147 ns = elem->nsDef;
6148 while (ns != NULL) {
6149 if (ns->prefix == NULL) {
6150 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006151 xmlErrValidNode(ctxt, elem,
6152 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00006153 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006154 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006155 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006156 }
6157 goto found;
6158 }
6159 ns = ns->next;
6160 }
6161 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6162 xmlNsPtr ns;
6163
6164 ns = elem->nsDef;
6165 while (ns != NULL) {
6166 if (xmlStrEqual(attr->name, ns->prefix)) {
6167 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006168 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006169 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006170 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006171 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006172 }
6173 goto found;
6174 }
6175 ns = ns->next;
6176 }
6177 }
Owen Taylor3473f882001-02-23 17:55:21 +00006178 }
6179found:
6180 attr = attr->nexth;
6181 }
6182 return(ret);
6183}
6184
6185/**
6186 * xmlValidateRoot:
6187 * @ctxt: the validation context
6188 * @doc: a document instance
6189 *
6190 * Try to validate a the root element
6191 * basically it does the following check as described by the
6192 * XML-1.0 recommendation:
6193 * - [ VC: Root Element Type ]
6194 * it doesn't try to recurse or apply other check to the element
6195 *
6196 * returns 1 if valid or 0 otherwise
6197 */
6198
6199int
6200xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6201 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006202 int ret;
6203
Owen Taylor3473f882001-02-23 17:55:21 +00006204 if (doc == NULL) return(0);
6205
6206 root = xmlDocGetRootElement(doc);
6207 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006208 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6209 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006210 return(0);
6211 }
6212
6213 /*
6214 * When doing post validation against a separate DTD, those may
6215 * no internal subset has been generated
6216 */
6217 if ((doc->intSubset != NULL) &&
6218 (doc->intSubset->name != NULL)) {
6219 /*
6220 * Check first the document root against the NQName
6221 */
6222 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6223 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006224 xmlChar fn[50];
6225 xmlChar *fullname;
6226
6227 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6228 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006229 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006230 return(0);
6231 }
6232 ret = xmlStrEqual(doc->intSubset->name, fullname);
6233 if ((fullname != fn) && (fullname != root->name))
6234 xmlFree(fullname);
6235 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006236 goto name_ok;
6237 }
6238 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6239 (xmlStrEqual(root->name, BAD_CAST "html")))
6240 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006241 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6242 "root and DTD name do not match '%s' and '%s'\n",
6243 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006244 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006245 }
6246 }
6247name_ok:
6248 return(1);
6249}
6250
6251
6252/**
6253 * xmlValidateElement:
6254 * @ctxt: the validation context
6255 * @doc: a document instance
6256 * @elem: an element instance
6257 *
6258 * Try to validate the subtree under an element
6259 *
6260 * returns 1 if valid or 0 otherwise
6261 */
6262
6263int
6264xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6265 xmlNodePtr child;
6266 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006267 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006268 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006269 int ret = 1;
6270
6271 if (elem == NULL) return(0);
6272
6273 /*
6274 * XInclude elements were added after parsing in the infoset,
6275 * they don't really mean anything validation wise.
6276 */
6277 if ((elem->type == XML_XINCLUDE_START) ||
6278 (elem->type == XML_XINCLUDE_END))
6279 return(1);
6280
6281 CHECK_DTD;
6282
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006283 /*
6284 * Entities references have to be handled separately
6285 */
6286 if (elem->type == XML_ENTITY_REF_NODE) {
6287 return(1);
6288 }
6289
Owen Taylor3473f882001-02-23 17:55:21 +00006290 ret &= xmlValidateOneElement(ctxt, doc, elem);
6291 attr = elem->properties;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006292 while (attr != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006293 value = xmlNodeListGetString(doc, attr->children, 0);
6294 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6295 if (value != NULL)
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006296 xmlFree((char *)value);
Owen Taylor3473f882001-02-23 17:55:21 +00006297 attr= attr->next;
6298 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006299 ns = elem->nsDef;
6300 while (ns != NULL) {
Daniel Veillard1f5c9892003-12-29 17:09:55 +00006301 if (elem->ns == NULL)
6302 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6303 ns, ns->href);
6304 else
6305 ret &= xmlValidateOneNamespace(ctxt, doc, elem, elem->ns->prefix,
6306 ns, ns->href);
Daniel Veillarde133dd82003-10-30 10:42:20 +00006307 ns = ns->next;
6308 }
Owen Taylor3473f882001-02-23 17:55:21 +00006309 child = elem->children;
6310 while (child != NULL) {
6311 ret &= xmlValidateElement(ctxt, doc, child);
6312 child = child->next;
6313 }
6314
6315 return(ret);
6316}
6317
Daniel Veillard8730c562001-02-26 10:49:57 +00006318/**
6319 * xmlValidateRef:
6320 * @ref: A reference to be validated
6321 * @ctxt: Validation context
6322 * @name: Name of ID we are searching for
6323 *
6324 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006325static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006326xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006327 const xmlChar *name) {
6328 xmlAttrPtr id;
6329 xmlAttrPtr attr;
6330
6331 if (ref == NULL)
6332 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006333 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006334 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006335 attr = ref->attr;
6336 if (attr == NULL) {
6337 xmlChar *dup, *str = NULL, *cur, save;
6338
6339 dup = xmlStrdup(name);
6340 if (dup == NULL) {
6341 ctxt->valid = 0;
6342 return;
6343 }
6344 cur = dup;
6345 while (*cur != 0) {
6346 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006347 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006348 save = *cur;
6349 *cur = 0;
6350 id = xmlGetID(ctxt->doc, str);
6351 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006352 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006353 "attribute %s line %d references an unknown ID \"%s\"\n",
6354 ref->name, ref->lineno, str);
6355 ctxt->valid = 0;
6356 }
6357 if (save == 0)
6358 break;
6359 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006360 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006361 }
6362 xmlFree(dup);
6363 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006364 id = xmlGetID(ctxt->doc, name);
6365 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006366 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006367 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006368 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006369 ctxt->valid = 0;
6370 }
6371 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6372 xmlChar *dup, *str = NULL, *cur, save;
6373
6374 dup = xmlStrdup(name);
6375 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006376 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006377 ctxt->valid = 0;
6378 return;
6379 }
6380 cur = dup;
6381 while (*cur != 0) {
6382 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006383 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006384 save = *cur;
6385 *cur = 0;
6386 id = xmlGetID(ctxt->doc, str);
6387 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006388 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006389 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006390 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006391 ctxt->valid = 0;
6392 }
6393 if (save == 0)
6394 break;
6395 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006396 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006397 }
6398 xmlFree(dup);
6399 }
6400}
6401
6402/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006403 * xmlWalkValidateList:
6404 * @data: Contents of current link
6405 * @user: Value supplied by the user
6406 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006407 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006408 */
6409static int
6410xmlWalkValidateList(const void *data, const void *user)
6411{
6412 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6413 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6414 return 1;
6415}
6416
6417/**
6418 * xmlValidateCheckRefCallback:
6419 * @ref_list: List of references
6420 * @ctxt: Validation context
6421 * @name: Name of ID we are searching for
6422 *
6423 */
6424static void
6425xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6426 const xmlChar *name) {
6427 xmlValidateMemo memo;
6428
6429 if (ref_list == NULL)
6430 return;
6431 memo.ctxt = ctxt;
6432 memo.name = name;
6433
6434 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6435
6436}
6437
6438/**
Owen Taylor3473f882001-02-23 17:55:21 +00006439 * xmlValidateDocumentFinal:
6440 * @ctxt: the validation context
6441 * @doc: a document instance
6442 *
6443 * Does the final step for the document validation once all the
6444 * incremental validation steps have been completed
6445 *
6446 * basically it does the following checks described by the XML Rec
6447 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006448 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006449 *
6450 * returns 1 if valid or 0 otherwise
6451 */
6452
6453int
6454xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6455 xmlRefTablePtr table;
6456
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006457 if (ctxt == NULL)
6458 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006459 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006460 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6461 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006462 return(0);
6463 }
6464
6465 /*
6466 * Check all the NOTATION/NOTATIONS attributes
6467 */
6468 /*
6469 * Check all the ENTITY/ENTITIES attributes definition for validity
6470 */
6471 /*
6472 * Check all the IDREF/IDREFS attributes definition for validity
6473 */
6474 table = (xmlRefTablePtr) doc->refs;
6475 ctxt->doc = doc;
6476 ctxt->valid = 1;
6477 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6478 return(ctxt->valid);
6479}
6480
6481/**
6482 * xmlValidateDtd:
6483 * @ctxt: the validation context
6484 * @doc: a document instance
6485 * @dtd: a dtd instance
6486 *
6487 * Try to validate the document against the dtd instance
6488 *
William M. Brack367df6e2004-10-23 18:14:36 +00006489 * Basically it does check all the definitions in the DtD.
6490 * Note the the internal subset (if present) is de-coupled
6491 * (i.e. not used), which could give problems if ID or IDREF
6492 * is present.
Owen Taylor3473f882001-02-23 17:55:21 +00006493 *
6494 * returns 1 if valid or 0 otherwise
6495 */
6496
6497int
6498xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6499 int ret;
William M. Brack367df6e2004-10-23 18:14:36 +00006500 xmlDtdPtr oldExt, oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006501 xmlNodePtr root;
6502
6503 if (dtd == NULL) return(0);
6504 if (doc == NULL) return(0);
6505 oldExt = doc->extSubset;
William M. Brack367df6e2004-10-23 18:14:36 +00006506 oldInt = doc->intSubset;
Owen Taylor3473f882001-02-23 17:55:21 +00006507 doc->extSubset = dtd;
William M. Brack367df6e2004-10-23 18:14:36 +00006508 doc->intSubset = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006509 ret = xmlValidateRoot(ctxt, doc);
6510 if (ret == 0) {
6511 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006512 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006513 return(ret);
6514 }
6515 if (doc->ids != NULL) {
6516 xmlFreeIDTable(doc->ids);
6517 doc->ids = NULL;
6518 }
6519 if (doc->refs != NULL) {
6520 xmlFreeRefTable(doc->refs);
6521 doc->refs = NULL;
6522 }
6523 root = xmlDocGetRootElement(doc);
6524 ret = xmlValidateElement(ctxt, doc, root);
6525 ret &= xmlValidateDocumentFinal(ctxt, doc);
6526 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006527 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006528 return(ret);
6529}
6530
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006531static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006532xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6533 const xmlChar *name ATTRIBUTE_UNUSED) {
6534 if (cur == NULL)
6535 return;
6536 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6537 xmlChar *notation = cur->content;
6538
Daniel Veillard878eab02002-02-19 13:46:09 +00006539 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006540 int ret;
6541
6542 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6543 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006544 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006545 }
6546 }
6547 }
6548}
6549
6550static void
Owen Taylor3473f882001-02-23 17:55:21 +00006551xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006552 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006553 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006554 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006555 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006556
Owen Taylor3473f882001-02-23 17:55:21 +00006557 if (cur == NULL)
6558 return;
6559 switch (cur->atype) {
6560 case XML_ATTRIBUTE_CDATA:
6561 case XML_ATTRIBUTE_ID:
6562 case XML_ATTRIBUTE_IDREF :
6563 case XML_ATTRIBUTE_IDREFS:
6564 case XML_ATTRIBUTE_NMTOKEN:
6565 case XML_ATTRIBUTE_NMTOKENS:
6566 case XML_ATTRIBUTE_ENUMERATION:
6567 break;
6568 case XML_ATTRIBUTE_ENTITY:
6569 case XML_ATTRIBUTE_ENTITIES:
6570 case XML_ATTRIBUTE_NOTATION:
6571 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006572
6573 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6574 cur->atype, cur->defaultValue);
6575 if ((ret == 0) && (ctxt->valid == 1))
6576 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006577 }
6578 if (cur->tree != NULL) {
6579 xmlEnumerationPtr tree = cur->tree;
6580 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006581 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006582 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006583 if ((ret == 0) && (ctxt->valid == 1))
6584 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006585 tree = tree->next;
6586 }
6587 }
6588 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006589 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6590 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006591 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006592 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006593 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006594 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006595 return;
6596 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006597
6598 if (doc != NULL)
6599 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6600 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006601 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006602 if ((elem == NULL) && (cur->parent != NULL) &&
6603 (cur->parent->type == XML_DTD_NODE))
6604 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006605 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006606 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006607 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006608 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006609 return;
6610 }
6611 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006612 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006613 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006614 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006615 ctxt->valid = 0;
6616 }
6617 }
Owen Taylor3473f882001-02-23 17:55:21 +00006618}
6619
6620/**
6621 * xmlValidateDtdFinal:
6622 * @ctxt: the validation context
6623 * @doc: a document instance
6624 *
6625 * Does the final step for the dtds validation once all the
6626 * subsets have been parsed
6627 *
6628 * basically it does the following checks described by the XML Rec
6629 * - check that ENTITY and ENTITIES type attributes default or
6630 * possible values matches one of the defined entities.
6631 * - check that NOTATION type attributes default or
6632 * possible values matches one of the defined notations.
6633 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006634 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006635 */
6636
6637int
6638xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006639 xmlDtdPtr dtd;
6640 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006641 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006642
6643 if (doc == NULL) return(0);
6644 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6645 return(0);
6646 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006647 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006648 dtd = doc->intSubset;
6649 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6650 table = (xmlAttributeTablePtr) dtd->attributes;
6651 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006652 }
6653 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006654 entities = (xmlEntitiesTablePtr) dtd->entities;
6655 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6656 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006657 }
6658 dtd = doc->extSubset;
6659 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6660 table = (xmlAttributeTablePtr) dtd->attributes;
6661 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006662 }
6663 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006664 entities = (xmlEntitiesTablePtr) dtd->entities;
6665 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6666 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006667 }
6668 return(ctxt->valid);
6669}
6670
6671/**
6672 * xmlValidateDocument:
6673 * @ctxt: the validation context
6674 * @doc: a document instance
6675 *
6676 * Try to validate the document instance
6677 *
6678 * basically it does the all the checks described by the XML Rec
6679 * i.e. validates the internal and external subset (if present)
6680 * and validate the document tree.
6681 *
6682 * returns 1 if valid or 0 otherwise
6683 */
6684
6685int
6686xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6687 int ret;
6688 xmlNodePtr root;
6689
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006690 if (doc == NULL)
6691 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006692 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006693 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6694 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006695 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006696 }
Owen Taylor3473f882001-02-23 17:55:21 +00006697 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6698 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
William M. Brack8c22f9f2004-08-06 16:23:27 +00006699 xmlChar *sysID;
6700 if (doc->intSubset->SystemID != NULL) {
William M. Brackbebe7302004-08-05 06:46:47 +00006701 sysID = xmlBuildURI(doc->intSubset->SystemID,
6702 doc->URL);
William M. Brack8c22f9f2004-08-06 16:23:27 +00006703 if (sysID == NULL) {
6704 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6705 "Could not build URI for external subset \"%s\"\n",
6706 (const char *) doc->intSubset->SystemID);
6707 return 0;
6708 }
6709 } else
William M. Brackbebe7302004-08-05 06:46:47 +00006710 sysID = NULL;
William M. Brack8c22f9f2004-08-06 16:23:27 +00006711 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
William M. Brackbebe7302004-08-05 06:46:47 +00006712 (const xmlChar *)sysID);
William M. Brackbebe7302004-08-05 06:46:47 +00006713 if (sysID != NULL)
6714 xmlFree(sysID);
Owen Taylor3473f882001-02-23 17:55:21 +00006715 if (doc->extSubset == NULL) {
6716 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006717 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006718 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006719 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006720 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006721 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006722 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006723 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006724 }
6725 return(0);
6726 }
6727 }
6728
6729 if (doc->ids != NULL) {
6730 xmlFreeIDTable(doc->ids);
6731 doc->ids = NULL;
6732 }
6733 if (doc->refs != NULL) {
6734 xmlFreeRefTable(doc->refs);
6735 doc->refs = NULL;
6736 }
6737 ret = xmlValidateDtdFinal(ctxt, doc);
6738 if (!xmlValidateRoot(ctxt, doc)) return(0);
6739
6740 root = xmlDocGetRootElement(doc);
6741 ret &= xmlValidateElement(ctxt, doc, root);
6742 ret &= xmlValidateDocumentFinal(ctxt, doc);
6743 return(ret);
6744}
6745
Owen Taylor3473f882001-02-23 17:55:21 +00006746/************************************************************************
6747 * *
6748 * Routines for dynamic validation editing *
6749 * *
6750 ************************************************************************/
6751
6752/**
6753 * xmlValidGetPotentialChildren:
6754 * @ctree: an element content tree
6755 * @list: an array to store the list of child names
6756 * @len: a pointer to the number of element in the list
6757 * @max: the size of the array
6758 *
6759 * Build/extend a list of potential children allowed by the content tree
6760 *
6761 * returns the number of element in the list, or -1 in case of error.
6762 */
6763
6764int
6765xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6766 int *len, int max) {
6767 int i;
6768
6769 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6770 return(-1);
6771 if (*len >= max) return(*len);
6772
6773 switch (ctree->type) {
6774 case XML_ELEMENT_CONTENT_PCDATA:
6775 for (i = 0; i < *len;i++)
6776 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6777 list[(*len)++] = BAD_CAST "#PCDATA";
6778 break;
6779 case XML_ELEMENT_CONTENT_ELEMENT:
6780 for (i = 0; i < *len;i++)
6781 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6782 list[(*len)++] = ctree->name;
6783 break;
6784 case XML_ELEMENT_CONTENT_SEQ:
6785 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6786 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6787 break;
6788 case XML_ELEMENT_CONTENT_OR:
6789 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6790 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6791 break;
6792 }
6793
6794 return(*len);
6795}
6796
William M. Brack9333cc22004-06-24 08:33:40 +00006797/*
6798 * Dummy function to suppress messages while we try out valid elements
6799 */
6800static void xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
6801 const char *msg ATTRIBUTE_UNUSED, ...) {
6802 return;
6803}
6804
Owen Taylor3473f882001-02-23 17:55:21 +00006805/**
6806 * xmlValidGetValidElements:
6807 * @prev: an element to insert after
6808 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006809 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006810 * @max: the size of the array
6811 *
6812 * This function returns the list of authorized children to insert
6813 * within an existing tree while respecting the validity constraints
6814 * forced by the Dtd. The insertion point is defined using @prev and
6815 * @next in the following ways:
6816 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6817 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6818 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6819 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6820 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6821 *
6822 * pointers to the element names are inserted at the beginning of the array
6823 * and do not need to be freed.
6824 *
6825 * returns the number of element in the list, or -1 in case of error. If
6826 * the function returns the value @max the caller is invited to grow the
6827 * receiving array and retry.
6828 */
6829
6830int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006831xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006832 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006833 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006834 int nb_valid_elements = 0;
6835 const xmlChar *elements[256];
6836 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006837 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006838
6839 xmlNode *ref_node;
6840 xmlNode *parent;
6841 xmlNode *test_node;
6842
6843 xmlNode *prev_next;
6844 xmlNode *next_prev;
6845 xmlNode *parent_childs;
6846 xmlNode *parent_last;
6847
6848 xmlElement *element_desc;
6849
6850 if (prev == NULL && next == NULL)
6851 return(-1);
6852
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006853 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006854 if (max <= 0) return(-1);
6855
William M. Brack9333cc22004-06-24 08:33:40 +00006856 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6857 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6858
Owen Taylor3473f882001-02-23 17:55:21 +00006859 nb_valid_elements = 0;
6860 ref_node = prev ? prev : next;
6861 parent = ref_node->parent;
6862
6863 /*
6864 * Retrieves the parent element declaration
6865 */
6866 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6867 parent->name);
6868 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6869 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6870 parent->name);
6871 if (element_desc == NULL) return(-1);
6872
6873 /*
6874 * Do a backup of the current tree structure
6875 */
6876 prev_next = prev ? prev->next : NULL;
6877 next_prev = next ? next->prev : NULL;
6878 parent_childs = parent->children;
6879 parent_last = parent->last;
6880
6881 /*
6882 * Creates a dummy node and insert it into the tree
6883 */
Daniel Veillard95ddcd32004-10-26 21:53:55 +00006884 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006885 test_node->parent = parent;
6886 test_node->prev = prev;
6887 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006888 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006889
6890 if (prev) prev->next = test_node;
6891 else parent->children = test_node;
6892
6893 if (next) next->prev = test_node;
6894 else parent->last = test_node;
6895
6896 /*
6897 * Insert each potential child node and check if the parent is
6898 * still valid
6899 */
6900 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6901 elements, &nb_elements, 256);
6902
6903 for (i = 0;i < nb_elements;i++) {
6904 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006905 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006906 int j;
6907
6908 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006909 if (xmlStrEqual(elements[i], names[j])) break;
6910 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00006911 if (nb_valid_elements >= max) break;
6912 }
6913 }
6914
6915 /*
6916 * Restore the tree structure
6917 */
6918 if (prev) prev->next = prev_next;
6919 if (next) next->prev = next_prev;
6920 parent->children = parent_childs;
6921 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006922
6923 /*
6924 * Free up the dummy node
6925 */
6926 test_node->name = name;
6927 xmlFreeNode(test_node);
6928
Owen Taylor3473f882001-02-23 17:55:21 +00006929 return(nb_valid_elements);
6930}
Daniel Veillard4432df22003-09-28 18:58:27 +00006931#endif /* LIBXML_VALID_ENABLED */
6932
Daniel Veillard5d4644e2005-04-01 13:11:58 +00006933#define bottom_valid
6934#include "elfgcchack.h"