blob: 5abdc92f526c27806f4440ff5f2ff2572d27e0d3 [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 */
1550 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
1551 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
1552 ret->content = content;
1553 if (content != NULL)
1554 content->parent = (xmlElementContentPtr) 1;
1555 } else {
1556 ret->content = xmlCopyDocElementContent(dtd->doc, content);
1557 }
Owen Taylor3473f882001-02-23 17:55:21 +00001558
1559 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001560 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001561 */
1562 ret->parent = dtd;
1563 ret->doc = dtd->doc;
1564 if (dtd->last == NULL) {
1565 dtd->children = dtd->last = (xmlNodePtr) ret;
1566 } else {
1567 dtd->last->next = (xmlNodePtr) ret;
1568 ret->prev = dtd->last;
1569 dtd->last = (xmlNodePtr) ret;
1570 }
1571 if (uqname != NULL)
1572 xmlFree(uqname);
1573 return(ret);
1574}
1575
1576/**
1577 * xmlFreeElementTable:
1578 * @table: An element table
1579 *
1580 * Deallocate the memory used by an element hash table.
1581 */
1582void
1583xmlFreeElementTable(xmlElementTablePtr table) {
1584 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1585}
1586
Daniel Veillard652327a2003-09-29 18:02:38 +00001587#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001588/**
1589 * xmlCopyElement:
1590 * @elem: An element
1591 *
1592 * Build a copy of an element.
1593 *
1594 * Returns the new xmlElementPtr or NULL in case of error.
1595 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001596static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001597xmlCopyElement(xmlElementPtr elem) {
1598 xmlElementPtr cur;
1599
1600 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1601 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001602 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001603 return(NULL);
1604 }
1605 memset(cur, 0, sizeof(xmlElement));
1606 cur->type = XML_ELEMENT_DECL;
1607 cur->etype = elem->etype;
1608 if (elem->name != NULL)
1609 cur->name = xmlStrdup(elem->name);
1610 else
1611 cur->name = NULL;
1612 if (elem->prefix != NULL)
1613 cur->prefix = xmlStrdup(elem->prefix);
1614 else
1615 cur->prefix = NULL;
1616 cur->content = xmlCopyElementContent(elem->content);
1617 /* TODO : rebuild the attribute list on the copy */
1618 cur->attributes = NULL;
1619 return(cur);
1620}
1621
1622/**
1623 * xmlCopyElementTable:
1624 * @table: An element table
1625 *
1626 * Build a copy of an element table.
1627 *
1628 * Returns the new xmlElementTablePtr or NULL in case of error.
1629 */
1630xmlElementTablePtr
1631xmlCopyElementTable(xmlElementTablePtr table) {
1632 return((xmlElementTablePtr) xmlHashCopy(table,
1633 (xmlHashCopier) xmlCopyElement));
1634}
Daniel Veillard652327a2003-09-29 18:02:38 +00001635#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001636
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001637#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001638/**
1639 * xmlDumpElementDecl:
1640 * @buf: the XML buffer output
1641 * @elem: An element table
1642 *
1643 * This will dump the content of the element declaration as an XML
1644 * DTD definition
1645 */
1646void
1647xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001648 if ((buf == NULL) || (elem == NULL))
1649 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001650 switch (elem->etype) {
1651 case XML_ELEMENT_TYPE_EMPTY:
1652 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001653 if (elem->prefix != NULL) {
1654 xmlBufferWriteCHAR(buf, elem->prefix);
1655 xmlBufferWriteChar(buf, ":");
1656 }
Owen Taylor3473f882001-02-23 17:55:21 +00001657 xmlBufferWriteCHAR(buf, elem->name);
1658 xmlBufferWriteChar(buf, " EMPTY>\n");
1659 break;
1660 case XML_ELEMENT_TYPE_ANY:
1661 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001662 if (elem->prefix != NULL) {
1663 xmlBufferWriteCHAR(buf, elem->prefix);
1664 xmlBufferWriteChar(buf, ":");
1665 }
Owen Taylor3473f882001-02-23 17:55:21 +00001666 xmlBufferWriteCHAR(buf, elem->name);
1667 xmlBufferWriteChar(buf, " ANY>\n");
1668 break;
1669 case XML_ELEMENT_TYPE_MIXED:
1670 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001671 if (elem->prefix != NULL) {
1672 xmlBufferWriteCHAR(buf, elem->prefix);
1673 xmlBufferWriteChar(buf, ":");
1674 }
Owen Taylor3473f882001-02-23 17:55:21 +00001675 xmlBufferWriteCHAR(buf, elem->name);
1676 xmlBufferWriteChar(buf, " ");
1677 xmlDumpElementContent(buf, elem->content, 1);
1678 xmlBufferWriteChar(buf, ">\n");
1679 break;
1680 case XML_ELEMENT_TYPE_ELEMENT:
1681 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001682 if (elem->prefix != NULL) {
1683 xmlBufferWriteCHAR(buf, elem->prefix);
1684 xmlBufferWriteChar(buf, ":");
1685 }
Owen Taylor3473f882001-02-23 17:55:21 +00001686 xmlBufferWriteCHAR(buf, elem->name);
1687 xmlBufferWriteChar(buf, " ");
1688 xmlDumpElementContent(buf, elem->content, 1);
1689 xmlBufferWriteChar(buf, ">\n");
1690 break;
1691 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001692 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1693 "Internal: ELEMENT struct corrupted invalid type\n",
1694 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001695 }
1696}
1697
1698/**
William M. Brack9e660592003-10-20 14:56:06 +00001699 * xmlDumpElementDeclScan:
1700 * @elem: An element table
1701 * @buf: the XML buffer output
1702 *
1703 * This routine is used by the hash scan function. It just reverses
1704 * the arguments.
1705 */
1706static void
1707xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1708 xmlDumpElementDecl(buf, elem);
1709}
1710
1711/**
Owen Taylor3473f882001-02-23 17:55:21 +00001712 * xmlDumpElementTable:
1713 * @buf: the XML buffer output
1714 * @table: An element table
1715 *
1716 * This will dump the content of the element table as an XML DTD definition
1717 */
1718void
1719xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001720 if ((buf == NULL) || (table == NULL))
1721 return;
William M. Brack9e660592003-10-20 14:56:06 +00001722 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001723}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001724#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001725
1726/**
1727 * xmlCreateEnumeration:
1728 * @name: the enumeration name or NULL
1729 *
1730 * create and initialize an enumeration attribute node.
1731 *
1732 * Returns the xmlEnumerationPtr just created or NULL in case
1733 * of error.
1734 */
1735xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001736xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001737 xmlEnumerationPtr ret;
1738
1739 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1740 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001741 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001742 return(NULL);
1743 }
1744 memset(ret, 0, sizeof(xmlEnumeration));
1745
1746 if (name != NULL)
1747 ret->name = xmlStrdup(name);
1748 return(ret);
1749}
1750
1751/**
1752 * xmlFreeEnumeration:
1753 * @cur: the tree to free.
1754 *
1755 * free an enumeration attribute node (recursive).
1756 */
1757void
1758xmlFreeEnumeration(xmlEnumerationPtr cur) {
1759 if (cur == NULL) return;
1760
1761 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1762
1763 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001764 xmlFree(cur);
1765}
1766
Daniel Veillard652327a2003-09-29 18:02:38 +00001767#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001768/**
1769 * xmlCopyEnumeration:
1770 * @cur: the tree to copy.
1771 *
1772 * Copy an enumeration attribute node (recursive).
1773 *
1774 * Returns the xmlEnumerationPtr just created or NULL in case
1775 * of error.
1776 */
1777xmlEnumerationPtr
1778xmlCopyEnumeration(xmlEnumerationPtr cur) {
1779 xmlEnumerationPtr ret;
1780
1781 if (cur == NULL) return(NULL);
1782 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1783
1784 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1785 else ret->next = NULL;
1786
1787 return(ret);
1788}
Daniel Veillard652327a2003-09-29 18:02:38 +00001789#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001790
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001791#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001792/**
1793 * xmlDumpEnumeration:
1794 * @buf: the XML buffer output
1795 * @enum: An enumeration
1796 *
1797 * This will dump the content of the enumeration
1798 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001799static void
Owen Taylor3473f882001-02-23 17:55:21 +00001800xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001801 if ((buf == NULL) || (cur == NULL))
1802 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001803
1804 xmlBufferWriteCHAR(buf, cur->name);
1805 if (cur->next == NULL)
1806 xmlBufferWriteChar(buf, ")");
1807 else {
1808 xmlBufferWriteChar(buf, " | ");
1809 xmlDumpEnumeration(buf, cur->next);
1810 }
1811}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001812#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001813
Daniel Veillard4432df22003-09-28 18:58:27 +00001814#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001815/**
1816 * xmlScanAttributeDeclCallback:
1817 * @attr: the attribute decl
1818 * @list: the list to update
1819 *
1820 * Callback called by xmlScanAttributeDecl when a new attribute
1821 * has to be entered in the list.
1822 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001823static void
Owen Taylor3473f882001-02-23 17:55:21 +00001824xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001825 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001826 attr->nexth = *list;
1827 *list = attr;
1828}
1829
1830/**
1831 * xmlScanAttributeDecl:
1832 * @dtd: pointer to the DTD
1833 * @elem: the element name
1834 *
1835 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001836 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001837 *
1838 * Returns the pointer to the first attribute decl in the chain,
1839 * possibly NULL.
1840 */
1841xmlAttributePtr
1842xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1843 xmlAttributePtr ret = NULL;
1844 xmlAttributeTablePtr table;
1845
1846 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001847 return(NULL);
1848 }
1849 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001850 return(NULL);
1851 }
1852 table = (xmlAttributeTablePtr) dtd->attributes;
1853 if (table == NULL)
1854 return(NULL);
1855
1856 /* WRONG !!! */
1857 xmlHashScan3(table, NULL, NULL, elem,
1858 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1859 return(ret);
1860}
1861
1862/**
1863 * xmlScanIDAttributeDecl:
1864 * @ctxt: the validation context
1865 * @elem: the element name
1866 *
1867 * Verify that the element don't have too many ID attributes
1868 * declared.
1869 *
1870 * Returns the number of ID attributes found.
1871 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001872static int
Owen Taylor3473f882001-02-23 17:55:21 +00001873xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1874 xmlAttributePtr cur;
1875 int ret = 0;
1876
1877 if (elem == NULL) return(0);
1878 cur = elem->attributes;
1879 while (cur != NULL) {
1880 if (cur->atype == XML_ATTRIBUTE_ID) {
1881 ret ++;
1882 if (ret > 1)
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001883 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001884 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001885 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001886 }
1887 cur = cur->nexth;
1888 }
1889 return(ret);
1890}
Daniel Veillard4432df22003-09-28 18:58:27 +00001891#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001892
1893/**
1894 * xmlFreeAttribute:
1895 * @elem: An attribute
1896 *
1897 * Deallocate the memory used by an attribute definition
1898 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001899static void
Owen Taylor3473f882001-02-23 17:55:21 +00001900xmlFreeAttribute(xmlAttributePtr attr) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001901 xmlDictPtr dict;
1902
Owen Taylor3473f882001-02-23 17:55:21 +00001903 if (attr == NULL) return;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001904 if (attr->doc != NULL)
1905 dict = attr->doc->dict;
1906 else
1907 dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001908 xmlUnlinkNode((xmlNodePtr) attr);
1909 if (attr->tree != NULL)
1910 xmlFreeEnumeration(attr->tree);
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001911 if (dict) {
1912 if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1913 xmlFree((xmlChar *) attr->elem);
1914 if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1915 xmlFree((xmlChar *) attr->name);
1916 if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1917 xmlFree((xmlChar *) attr->prefix);
1918 if ((attr->defaultValue != NULL) &&
1919 (!xmlDictOwns(dict, attr->defaultValue)))
1920 xmlFree((xmlChar *) attr->defaultValue);
1921 } else {
1922 if (attr->elem != NULL)
1923 xmlFree((xmlChar *) attr->elem);
1924 if (attr->name != NULL)
1925 xmlFree((xmlChar *) attr->name);
1926 if (attr->defaultValue != NULL)
1927 xmlFree((xmlChar *) attr->defaultValue);
1928 if (attr->prefix != NULL)
1929 xmlFree((xmlChar *) attr->prefix);
1930 }
Owen Taylor3473f882001-02-23 17:55:21 +00001931 xmlFree(attr);
1932}
1933
1934
1935/**
1936 * xmlAddAttributeDecl:
1937 * @ctxt: the validation context
1938 * @dtd: pointer to the DTD
1939 * @elem: the element name
1940 * @name: the attribute name
1941 * @ns: the attribute namespace prefix
1942 * @type: the attribute type
1943 * @def: the attribute default type
1944 * @defaultValue: the attribute default value
1945 * @tree: if it's an enumeration, the associated list
1946 *
1947 * Register a new attribute declaration
1948 * Note that @tree becomes the ownership of the DTD
1949 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001950 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001951 */
1952xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001953xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001954 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001955 const xmlChar *name, const xmlChar *ns,
1956 xmlAttributeType type, xmlAttributeDefault def,
1957 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1958 xmlAttributePtr ret;
1959 xmlAttributeTablePtr table;
1960 xmlElementPtr elemDef;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001961 xmlDictPtr dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001962
1963 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001964 xmlFreeEnumeration(tree);
1965 return(NULL);
1966 }
1967 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001968 xmlFreeEnumeration(tree);
1969 return(NULL);
1970 }
1971 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001972 xmlFreeEnumeration(tree);
1973 return(NULL);
1974 }
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001975 if (dtd->doc != NULL)
1976 dict = dtd->doc->dict;
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001977
Daniel Veillard4432df22003-09-28 18:58:27 +00001978#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001979 /*
1980 * Check the type and possibly the default value.
1981 */
1982 switch (type) {
1983 case XML_ATTRIBUTE_CDATA:
1984 break;
1985 case XML_ATTRIBUTE_ID:
1986 break;
1987 case XML_ATTRIBUTE_IDREF:
1988 break;
1989 case XML_ATTRIBUTE_IDREFS:
1990 break;
1991 case XML_ATTRIBUTE_ENTITY:
1992 break;
1993 case XML_ATTRIBUTE_ENTITIES:
1994 break;
1995 case XML_ATTRIBUTE_NMTOKEN:
1996 break;
1997 case XML_ATTRIBUTE_NMTOKENS:
1998 break;
1999 case XML_ATTRIBUTE_ENUMERATION:
2000 break;
2001 case XML_ATTRIBUTE_NOTATION:
2002 break;
2003 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002004 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
2005 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2006 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002007 xmlFreeEnumeration(tree);
2008 return(NULL);
2009 }
2010 if ((defaultValue != NULL) &&
2011 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002012 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
2013 "Attribute %s of %s: invalid default value\n",
2014 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00002015 defaultValue = NULL;
Daniel Veillard42595322004-11-08 10:52:06 +00002016 if (ctxt != NULL)
2017 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002018 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002019#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002020
2021 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00002022 * Check first that an attribute defined in the external subset wasn't
2023 * already defined in the internal subset
2024 */
2025 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2026 (dtd->doc->intSubset != NULL) &&
2027 (dtd->doc->intSubset->attributes != NULL)) {
2028 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2029 if (ret != NULL)
2030 return(NULL);
2031 }
2032
2033 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002034 * Create the Attribute table if needed.
2035 */
2036 table = (xmlAttributeTablePtr) dtd->attributes;
2037 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00002038 table = xmlHashCreateDict(0, dict);
Owen Taylor3473f882001-02-23 17:55:21 +00002039 dtd->attributes = (void *) table;
2040 }
2041 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002042 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002043 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002044 return(NULL);
2045 }
2046
2047
2048 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2049 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002050 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002051 return(NULL);
2052 }
2053 memset(ret, 0, sizeof(xmlAttribute));
2054 ret->type = XML_ATTRIBUTE_DECL;
2055
2056 /*
2057 * fill the structure.
2058 */
2059 ret->atype = type;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002060 if (dict) {
2061 ret->name = xmlDictLookup(dict, name, -1);
2062 ret->prefix = xmlDictLookup(dict, ns, -1);
2063 ret->elem = xmlDictLookup(dict, elem, -1);
2064 } else {
2065 ret->name = xmlStrdup(name);
2066 ret->prefix = xmlStrdup(ns);
2067 ret->elem = xmlStrdup(elem);
2068 }
Owen Taylor3473f882001-02-23 17:55:21 +00002069 ret->def = def;
2070 ret->tree = tree;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002071 if (defaultValue != NULL) {
2072 if (dict)
2073 ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2074 else
2075 ret->defaultValue = xmlStrdup(defaultValue);
2076 }
Owen Taylor3473f882001-02-23 17:55:21 +00002077
2078 /*
2079 * Validity Check:
2080 * Search the DTD for previous declarations of the ATTLIST
2081 */
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002082 if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002083#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002084 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002085 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002086 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002087 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00002088 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002089 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00002090#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002091 xmlFreeAttribute(ret);
2092 return(NULL);
2093 }
2094
2095 /*
2096 * Validity Check:
2097 * Multiple ID per element
2098 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00002099 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002100 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00002101
Daniel Veillard4432df22003-09-28 18:58:27 +00002102#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002103 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00002104 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002105 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00002106 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002107 elem, name, NULL);
Daniel Veillard42595322004-11-08 10:52:06 +00002108 if (ctxt != NULL)
2109 ctxt->valid = 0;
Daniel Veillardc7612992002-02-17 22:47:37 +00002110 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002111#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00002112
Daniel Veillard48da9102001-08-07 01:10:10 +00002113 /*
2114 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002115 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00002116 */
2117 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2118 ((ret->prefix != NULL &&
2119 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2120 ret->nexth = elemDef->attributes;
2121 elemDef->attributes = ret;
2122 } else {
2123 xmlAttributePtr tmp = elemDef->attributes;
2124
2125 while ((tmp != NULL) &&
2126 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2127 ((ret->prefix != NULL &&
2128 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2129 if (tmp->nexth == NULL)
2130 break;
2131 tmp = tmp->nexth;
2132 }
2133 if (tmp != NULL) {
2134 ret->nexth = tmp->nexth;
2135 tmp->nexth = ret;
2136 } else {
2137 ret->nexth = elemDef->attributes;
2138 elemDef->attributes = ret;
2139 }
2140 }
Owen Taylor3473f882001-02-23 17:55:21 +00002141 }
2142
2143 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002144 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00002145 */
2146 ret->parent = dtd;
2147 ret->doc = dtd->doc;
2148 if (dtd->last == NULL) {
2149 dtd->children = dtd->last = (xmlNodePtr) ret;
2150 } else {
2151 dtd->last->next = (xmlNodePtr) ret;
2152 ret->prev = dtd->last;
2153 dtd->last = (xmlNodePtr) ret;
2154 }
2155 return(ret);
2156}
2157
2158/**
2159 * xmlFreeAttributeTable:
2160 * @table: An attribute table
2161 *
2162 * Deallocate the memory used by an entities hash table.
2163 */
2164void
2165xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2166 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
2167}
2168
Daniel Veillard652327a2003-09-29 18:02:38 +00002169#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002170/**
2171 * xmlCopyAttribute:
2172 * @attr: An attribute
2173 *
2174 * Build a copy of an attribute.
2175 *
2176 * Returns the new xmlAttributePtr or NULL in case of error.
2177 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002178static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002179xmlCopyAttribute(xmlAttributePtr attr) {
2180 xmlAttributePtr cur;
2181
2182 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2183 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002184 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002185 return(NULL);
2186 }
2187 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00002188 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00002189 cur->atype = attr->atype;
2190 cur->def = attr->def;
2191 cur->tree = xmlCopyEnumeration(attr->tree);
2192 if (attr->elem != NULL)
2193 cur->elem = xmlStrdup(attr->elem);
2194 if (attr->name != NULL)
2195 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002196 if (attr->prefix != NULL)
2197 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002198 if (attr->defaultValue != NULL)
2199 cur->defaultValue = xmlStrdup(attr->defaultValue);
2200 return(cur);
2201}
2202
2203/**
2204 * xmlCopyAttributeTable:
2205 * @table: An attribute table
2206 *
2207 * Build a copy of an attribute table.
2208 *
2209 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2210 */
2211xmlAttributeTablePtr
2212xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2213 return((xmlAttributeTablePtr) xmlHashCopy(table,
2214 (xmlHashCopier) xmlCopyAttribute));
2215}
Daniel Veillard652327a2003-09-29 18:02:38 +00002216#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002217
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002218#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002219/**
2220 * xmlDumpAttributeDecl:
2221 * @buf: the XML buffer output
2222 * @attr: An attribute declaration
2223 *
2224 * This will dump the content of the attribute declaration as an XML
2225 * DTD definition
2226 */
2227void
2228xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002229 if ((buf == NULL) || (attr == NULL))
2230 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002231 xmlBufferWriteChar(buf, "<!ATTLIST ");
2232 xmlBufferWriteCHAR(buf, attr->elem);
2233 xmlBufferWriteChar(buf, " ");
2234 if (attr->prefix != NULL) {
2235 xmlBufferWriteCHAR(buf, attr->prefix);
2236 xmlBufferWriteChar(buf, ":");
2237 }
2238 xmlBufferWriteCHAR(buf, attr->name);
2239 switch (attr->atype) {
2240 case XML_ATTRIBUTE_CDATA:
2241 xmlBufferWriteChar(buf, " CDATA");
2242 break;
2243 case XML_ATTRIBUTE_ID:
2244 xmlBufferWriteChar(buf, " ID");
2245 break;
2246 case XML_ATTRIBUTE_IDREF:
2247 xmlBufferWriteChar(buf, " IDREF");
2248 break;
2249 case XML_ATTRIBUTE_IDREFS:
2250 xmlBufferWriteChar(buf, " IDREFS");
2251 break;
2252 case XML_ATTRIBUTE_ENTITY:
2253 xmlBufferWriteChar(buf, " ENTITY");
2254 break;
2255 case XML_ATTRIBUTE_ENTITIES:
2256 xmlBufferWriteChar(buf, " ENTITIES");
2257 break;
2258 case XML_ATTRIBUTE_NMTOKEN:
2259 xmlBufferWriteChar(buf, " NMTOKEN");
2260 break;
2261 case XML_ATTRIBUTE_NMTOKENS:
2262 xmlBufferWriteChar(buf, " NMTOKENS");
2263 break;
2264 case XML_ATTRIBUTE_ENUMERATION:
2265 xmlBufferWriteChar(buf, " (");
2266 xmlDumpEnumeration(buf, attr->tree);
2267 break;
2268 case XML_ATTRIBUTE_NOTATION:
2269 xmlBufferWriteChar(buf, " NOTATION (");
2270 xmlDumpEnumeration(buf, attr->tree);
2271 break;
2272 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002273 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2274 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2275 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002276 }
2277 switch (attr->def) {
2278 case XML_ATTRIBUTE_NONE:
2279 break;
2280 case XML_ATTRIBUTE_REQUIRED:
2281 xmlBufferWriteChar(buf, " #REQUIRED");
2282 break;
2283 case XML_ATTRIBUTE_IMPLIED:
2284 xmlBufferWriteChar(buf, " #IMPLIED");
2285 break;
2286 case XML_ATTRIBUTE_FIXED:
2287 xmlBufferWriteChar(buf, " #FIXED");
2288 break;
2289 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002290 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2291 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2292 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002293 }
2294 if (attr->defaultValue != NULL) {
2295 xmlBufferWriteChar(buf, " ");
2296 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2297 }
2298 xmlBufferWriteChar(buf, ">\n");
2299}
2300
2301/**
William M. Brack9e660592003-10-20 14:56:06 +00002302 * xmlDumpAttributeDeclScan:
2303 * @attr: An attribute declaration
2304 * @buf: the XML buffer output
2305 *
2306 * This is used with the hash scan function - just reverses arguments
2307 */
2308static void
2309xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2310 xmlDumpAttributeDecl(buf, attr);
2311}
2312
2313/**
Owen Taylor3473f882001-02-23 17:55:21 +00002314 * xmlDumpAttributeTable:
2315 * @buf: the XML buffer output
2316 * @table: An attribute table
2317 *
2318 * This will dump the content of the attribute table as an XML DTD definition
2319 */
2320void
2321xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002322 if ((buf == NULL) || (table == NULL))
2323 return;
William M. Brack9e660592003-10-20 14:56:06 +00002324 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002325}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002326#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002327
2328/************************************************************************
2329 * *
2330 * NOTATIONs *
2331 * *
2332 ************************************************************************/
2333/**
Owen Taylor3473f882001-02-23 17:55:21 +00002334 * xmlFreeNotation:
2335 * @not: A notation
2336 *
2337 * Deallocate the memory used by an notation definition
2338 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002339static void
Owen Taylor3473f882001-02-23 17:55:21 +00002340xmlFreeNotation(xmlNotationPtr nota) {
2341 if (nota == NULL) return;
2342 if (nota->name != NULL)
2343 xmlFree((xmlChar *) nota->name);
2344 if (nota->PublicID != NULL)
2345 xmlFree((xmlChar *) nota->PublicID);
2346 if (nota->SystemID != NULL)
2347 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002348 xmlFree(nota);
2349}
2350
2351
2352/**
2353 * xmlAddNotationDecl:
2354 * @dtd: pointer to the DTD
2355 * @ctxt: the validation context
2356 * @name: the entity name
2357 * @PublicID: the public identifier or NULL
2358 * @SystemID: the system identifier or NULL
2359 *
2360 * Register a new notation declaration
2361 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002362 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002363 */
2364xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002365xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002366 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002367 const xmlChar *PublicID, const xmlChar *SystemID) {
2368 xmlNotationPtr ret;
2369 xmlNotationTablePtr table;
2370
2371 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002372 return(NULL);
2373 }
2374 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002375 return(NULL);
2376 }
2377 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002378 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002379 }
2380
2381 /*
2382 * Create the Notation table if needed.
2383 */
2384 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002385 if (table == NULL) {
2386 xmlDictPtr dict = NULL;
2387 if (dtd->doc != NULL)
2388 dict = dtd->doc->dict;
2389
2390 dtd->notations = table = xmlHashCreateDict(0, dict);
2391 }
Owen Taylor3473f882001-02-23 17:55:21 +00002392 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002393 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002394 "xmlAddNotationDecl: Table creation failed!\n");
2395 return(NULL);
2396 }
2397
2398 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2399 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002400 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002401 return(NULL);
2402 }
2403 memset(ret, 0, sizeof(xmlNotation));
2404
2405 /*
2406 * fill the structure.
2407 */
2408 ret->name = xmlStrdup(name);
2409 if (SystemID != NULL)
2410 ret->SystemID = xmlStrdup(SystemID);
2411 if (PublicID != NULL)
2412 ret->PublicID = xmlStrdup(PublicID);
2413
2414 /*
2415 * Validity Check:
2416 * Check the DTD for previous declarations of the ATTLIST
2417 */
2418 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002419#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002420 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2421 "xmlAddNotationDecl: %s already defined\n",
2422 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002423#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002424 xmlFreeNotation(ret);
2425 return(NULL);
2426 }
2427 return(ret);
2428}
2429
2430/**
2431 * xmlFreeNotationTable:
2432 * @table: An notation table
2433 *
2434 * Deallocate the memory used by an entities hash table.
2435 */
2436void
2437xmlFreeNotationTable(xmlNotationTablePtr table) {
2438 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2439}
2440
Daniel Veillard652327a2003-09-29 18:02:38 +00002441#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002442/**
2443 * xmlCopyNotation:
2444 * @nota: A notation
2445 *
2446 * Build a copy of a notation.
2447 *
2448 * Returns the new xmlNotationPtr or NULL in case of error.
2449 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002450static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002451xmlCopyNotation(xmlNotationPtr nota) {
2452 xmlNotationPtr cur;
2453
2454 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2455 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002456 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002457 return(NULL);
2458 }
2459 if (nota->name != NULL)
2460 cur->name = xmlStrdup(nota->name);
2461 else
2462 cur->name = NULL;
2463 if (nota->PublicID != NULL)
2464 cur->PublicID = xmlStrdup(nota->PublicID);
2465 else
2466 cur->PublicID = NULL;
2467 if (nota->SystemID != NULL)
2468 cur->SystemID = xmlStrdup(nota->SystemID);
2469 else
2470 cur->SystemID = NULL;
2471 return(cur);
2472}
2473
2474/**
2475 * xmlCopyNotationTable:
2476 * @table: A notation table
2477 *
2478 * Build a copy of a notation table.
2479 *
2480 * Returns the new xmlNotationTablePtr or NULL in case of error.
2481 */
2482xmlNotationTablePtr
2483xmlCopyNotationTable(xmlNotationTablePtr table) {
2484 return((xmlNotationTablePtr) xmlHashCopy(table,
2485 (xmlHashCopier) xmlCopyNotation));
2486}
Daniel Veillard652327a2003-09-29 18:02:38 +00002487#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002488
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002489#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002490/**
2491 * xmlDumpNotationDecl:
2492 * @buf: the XML buffer output
2493 * @nota: A notation declaration
2494 *
2495 * This will dump the content the notation declaration as an XML DTD definition
2496 */
2497void
2498xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002499 if ((buf == NULL) || (nota == NULL))
2500 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002501 xmlBufferWriteChar(buf, "<!NOTATION ");
2502 xmlBufferWriteCHAR(buf, nota->name);
2503 if (nota->PublicID != NULL) {
2504 xmlBufferWriteChar(buf, " PUBLIC ");
2505 xmlBufferWriteQuotedString(buf, nota->PublicID);
2506 if (nota->SystemID != NULL) {
2507 xmlBufferWriteChar(buf, " ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002508 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002509 }
2510 } else {
2511 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002512 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002513 }
2514 xmlBufferWriteChar(buf, " >\n");
2515}
2516
2517/**
William M. Brack9e660592003-10-20 14:56:06 +00002518 * xmlDumpNotationDeclScan:
2519 * @nota: A notation declaration
2520 * @buf: the XML buffer output
2521 *
2522 * This is called with the hash scan function, and just reverses args
2523 */
2524static void
2525xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2526 xmlDumpNotationDecl(buf, nota);
2527}
2528
2529/**
Owen Taylor3473f882001-02-23 17:55:21 +00002530 * xmlDumpNotationTable:
2531 * @buf: the XML buffer output
2532 * @table: A notation table
2533 *
2534 * This will dump the content of the notation table as an XML DTD definition
2535 */
2536void
2537xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002538 if ((buf == NULL) || (table == NULL))
2539 return;
William M. Brack9e660592003-10-20 14:56:06 +00002540 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002541}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002542#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002543
2544/************************************************************************
2545 * *
2546 * IDs *
2547 * *
2548 ************************************************************************/
2549/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002550 * DICT_FREE:
2551 * @str: a string
2552 *
2553 * Free a string if it is not owned by the "dict" dictionnary in the
2554 * current scope
2555 */
2556#define DICT_FREE(str) \
2557 if ((str) && ((!dict) || \
2558 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2559 xmlFree((char *)(str));
2560
2561/**
Owen Taylor3473f882001-02-23 17:55:21 +00002562 * xmlFreeID:
2563 * @not: A id
2564 *
2565 * Deallocate the memory used by an id definition
2566 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002567static void
Owen Taylor3473f882001-02-23 17:55:21 +00002568xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002569 xmlDictPtr dict = NULL;
2570
Owen Taylor3473f882001-02-23 17:55:21 +00002571 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002572
2573 if (id->doc != NULL)
2574 dict = id->doc->dict;
2575
Owen Taylor3473f882001-02-23 17:55:21 +00002576 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002577 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002578 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002579 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002580 xmlFree(id);
2581}
2582
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002583
Owen Taylor3473f882001-02-23 17:55:21 +00002584/**
2585 * xmlAddID:
2586 * @ctxt: the validation context
2587 * @doc: pointer to the document
2588 * @value: the value name
2589 * @attr: the attribute holding the ID
2590 *
2591 * Register a new id declaration
2592 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002593 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002594 */
2595xmlIDPtr
2596xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2597 xmlAttrPtr attr) {
2598 xmlIDPtr ret;
2599 xmlIDTablePtr table;
2600
2601 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002602 return(NULL);
2603 }
2604 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002605 return(NULL);
2606 }
2607 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002608 return(NULL);
2609 }
2610
2611 /*
2612 * Create the ID table if needed.
2613 */
2614 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002615 if (table == NULL) {
2616 doc->ids = table = xmlHashCreateDict(0, doc->dict);
2617 }
Owen Taylor3473f882001-02-23 17:55:21 +00002618 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002619 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002620 "xmlAddID: Table creation failed!\n");
2621 return(NULL);
2622 }
2623
2624 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2625 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002626 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002627 return(NULL);
2628 }
2629
2630 /*
2631 * fill the structure.
2632 */
2633 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002634 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002635 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2636 /*
2637 * Operating in streaming mode, attr is gonna disapear
2638 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002639 if (doc->dict != NULL)
2640 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2641 else
2642 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002643 ret->attr = NULL;
2644 } else {
2645 ret->attr = attr;
2646 ret->name = NULL;
2647 }
2648 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002649
2650 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002651#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002652 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002653 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002654 */
Daniel Veillardd3669b22004-02-25 12:34:55 +00002655 if ((ctxt != NULL) && (ctxt->error != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002656 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2657 "ID %s already defined\n",
2658 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002659 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002660#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002661 xmlFreeID(ret);
2662 return(NULL);
2663 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002664 if (attr != NULL)
2665 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002666 return(ret);
2667}
2668
2669/**
2670 * xmlFreeIDTable:
2671 * @table: An id table
2672 *
2673 * Deallocate the memory used by an ID hash table.
2674 */
2675void
2676xmlFreeIDTable(xmlIDTablePtr table) {
2677 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2678}
2679
2680/**
2681 * xmlIsID:
2682 * @doc: the document
2683 * @elem: the element carrying the attribute
2684 * @attr: the attribute
2685 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002686 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002687 * then this is done if DTD loading has been requested. In the case
2688 * of HTML documents parsed with the HTML parser, then ID detection is
2689 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002690 *
2691 * Returns 0 or 1 depending on the lookup result
2692 */
2693int
2694xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2695 if (doc == NULL) return(0);
2696 if (attr == NULL) return(0);
2697 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2698 return(0);
2699 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard9ba8e382003-10-28 21:31:45 +00002700 if (((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2701 (xmlStrEqual(BAD_CAST "name", attr->name))) &&
2702 ((elem != NULL) && (!xmlStrEqual(elem->name, BAD_CAST "input"))))
Owen Taylor3473f882001-02-23 17:55:21 +00002703 return(1);
2704 return(0);
2705 } else {
2706 xmlAttributePtr attrDecl;
2707
2708 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002709 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002710 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002711 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002712
2713 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002714 if (fullname == NULL)
2715 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002716 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2717 attr->name);
2718 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2719 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2720 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002721 if ((fullname != fn) && (fullname != elem->name))
2722 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002723 } else {
2724 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2725 attr->name);
2726 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2727 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2728 attr->name);
2729 }
Owen Taylor3473f882001-02-23 17:55:21 +00002730
2731 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2732 return(1);
2733 }
2734 return(0);
2735}
2736
2737/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002738 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002739 * @doc: the document
2740 * @attr: the attribute
2741 *
2742 * Remove the given attribute from the ID table maintained internally.
2743 *
2744 * Returns -1 if the lookup failed and 0 otherwise
2745 */
2746int
2747xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002748 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002749 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002750 xmlChar *ID;
2751
2752 if (doc == NULL) return(-1);
2753 if (attr == NULL) return(-1);
2754 table = (xmlIDTablePtr) doc->ids;
2755 if (table == NULL)
2756 return(-1);
2757
2758 if (attr == NULL)
2759 return(-1);
2760 ID = xmlNodeListGetString(doc, attr->children, 1);
2761 if (ID == NULL)
2762 return(-1);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002763 id = xmlHashLookup(table, ID);
2764 if (id == NULL || id->attr != attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002765 xmlFree(ID);
2766 return(-1);
2767 }
Daniel Veillard91b955c2004-12-10 10:26:42 +00002768 xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID);
Owen Taylor3473f882001-02-23 17:55:21 +00002769 xmlFree(ID);
2770 return(0);
2771}
2772
2773/**
2774 * xmlGetID:
2775 * @doc: pointer to the document
2776 * @ID: the ID value
2777 *
2778 * Search the attribute declaring the given ID
2779 *
2780 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2781 */
2782xmlAttrPtr
2783xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2784 xmlIDTablePtr table;
2785 xmlIDPtr id;
2786
2787 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002788 return(NULL);
2789 }
2790
2791 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002792 return(NULL);
2793 }
2794
2795 table = (xmlIDTablePtr) doc->ids;
2796 if (table == NULL)
2797 return(NULL);
2798
2799 id = xmlHashLookup(table, ID);
2800 if (id == NULL)
2801 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002802 if (id->attr == NULL) {
2803 /*
2804 * We are operating on a stream, return a well known reference
2805 * since the attribute node doesn't exist anymore
2806 */
2807 return((xmlAttrPtr) doc);
2808 }
Owen Taylor3473f882001-02-23 17:55:21 +00002809 return(id->attr);
2810}
2811
2812/************************************************************************
2813 * *
2814 * Refs *
2815 * *
2816 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002817typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002818{
2819 xmlListPtr l;
2820 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002821} xmlRemoveMemo;
2822
2823typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2824
2825typedef struct xmlValidateMemo_t
2826{
2827 xmlValidCtxtPtr ctxt;
2828 const xmlChar *name;
2829} xmlValidateMemo;
2830
2831typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002832
2833/**
Owen Taylor3473f882001-02-23 17:55:21 +00002834 * xmlFreeRef:
2835 * @lk: A list link
2836 *
2837 * Deallocate the memory used by a ref definition
2838 */
2839static void
2840xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002841 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2842 if (ref == NULL) return;
2843 if (ref->value != NULL)
2844 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002845 if (ref->name != NULL)
2846 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002847 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002848}
2849
2850/**
2851 * xmlFreeRefList:
2852 * @list_ref: A list of references.
2853 *
2854 * Deallocate the memory used by a list of references
2855 */
2856static void
2857xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002858 if (list_ref == NULL) return;
2859 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002860}
2861
2862/**
2863 * xmlWalkRemoveRef:
2864 * @data: Contents of current link
2865 * @user: Value supplied by the user
2866 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002867 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002868 */
2869static int
2870xmlWalkRemoveRef(const void *data, const void *user)
2871{
Daniel Veillard37721922001-05-04 15:21:12 +00002872 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2873 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2874 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002875
Daniel Veillard37721922001-05-04 15:21:12 +00002876 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2877 xmlListRemoveFirst(ref_list, (void *)data);
2878 return 0;
2879 }
2880 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002881}
2882
2883/**
Daniel Veillard770075b2004-02-25 10:44:30 +00002884 * xmlDummyCompare
2885 * @data0: Value supplied by the user
2886 * @data1: Value supplied by the user
2887 *
2888 * Do nothing, return 0. Used to create unordered lists.
2889 */
2890static int
Daniel Veillardf54cd532004-02-25 11:52:31 +00002891xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2892 const void *data1 ATTRIBUTE_UNUSED)
Daniel Veillard770075b2004-02-25 10:44:30 +00002893{
2894 return (0);
2895}
2896
2897/**
Owen Taylor3473f882001-02-23 17:55:21 +00002898 * xmlAddRef:
2899 * @ctxt: the validation context
2900 * @doc: pointer to the document
2901 * @value: the value name
2902 * @attr: the attribute holding the Ref
2903 *
2904 * Register a new ref declaration
2905 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002906 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002907 */
2908xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002909xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002910 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002911 xmlRefPtr ret;
2912 xmlRefTablePtr table;
2913 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002914
Daniel Veillard37721922001-05-04 15:21:12 +00002915 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002916 return(NULL);
2917 }
2918 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002919 return(NULL);
2920 }
2921 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002922 return(NULL);
2923 }
Owen Taylor3473f882001-02-23 17:55:21 +00002924
Daniel Veillard37721922001-05-04 15:21:12 +00002925 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002926 * Create the Ref table if needed.
2927 */
Daniel Veillard37721922001-05-04 15:21:12 +00002928 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002929 if (table == NULL) {
2930 doc->refs = table = xmlHashCreateDict(0, doc->dict);
2931 }
Daniel Veillard37721922001-05-04 15:21:12 +00002932 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002933 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002934 "xmlAddRef: Table creation failed!\n");
2935 return(NULL);
2936 }
Owen Taylor3473f882001-02-23 17:55:21 +00002937
Daniel Veillard37721922001-05-04 15:21:12 +00002938 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2939 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002940 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002941 return(NULL);
2942 }
Owen Taylor3473f882001-02-23 17:55:21 +00002943
Daniel Veillard37721922001-05-04 15:21:12 +00002944 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002945 * fill the structure.
2946 */
Daniel Veillard37721922001-05-04 15:21:12 +00002947 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002948 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2949 /*
2950 * Operating in streaming mode, attr is gonna disapear
2951 */
2952 ret->name = xmlStrdup(attr->name);
2953 ret->attr = NULL;
2954 } else {
2955 ret->name = NULL;
2956 ret->attr = attr;
2957 }
2958 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002959
Daniel Veillard37721922001-05-04 15:21:12 +00002960 /* To add a reference :-
2961 * References are maintained as a list of references,
2962 * Lookup the entry, if no entry create new nodelist
2963 * Add the owning node to the NodeList
2964 * Return the ref
2965 */
Owen Taylor3473f882001-02-23 17:55:21 +00002966
Daniel Veillard37721922001-05-04 15:21:12 +00002967 if (NULL == (ref_list = xmlHashLookup(table, value))) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002968 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002969 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2970 "xmlAddRef: Reference list creation failed!\n",
2971 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002972 return(NULL);
2973 }
2974 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2975 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002976 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2977 "xmlAddRef: Reference list insertion failed!\n",
2978 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002979 return(NULL);
2980 }
2981 }
Daniel Veillard965983a2004-02-17 16:30:24 +00002982/* xmlListInsert(ref_list, ret); */
2983 xmlListAppend(ref_list, ret);
Daniel Veillard37721922001-05-04 15:21:12 +00002984 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002985}
2986
2987/**
2988 * xmlFreeRefTable:
2989 * @table: An ref table
2990 *
2991 * Deallocate the memory used by an Ref hash table.
2992 */
2993void
2994xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002995 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002996}
2997
2998/**
2999 * xmlIsRef:
3000 * @doc: the document
3001 * @elem: the element carrying the attribute
3002 * @attr: the attribute
3003 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003004 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00003005 * then this is simple, otherwise we use an heuristic: name Ref (upper
3006 * or lowercase).
3007 *
3008 * Returns 0 or 1 depending on the lookup result
3009 */
3010int
3011xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003012 if (attr == NULL)
3013 return(0);
3014 if (doc == NULL) {
3015 doc = attr->doc;
3016 if (doc == NULL) return(0);
3017 }
3018
Daniel Veillard37721922001-05-04 15:21:12 +00003019 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3020 return(0);
3021 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3022 /* TODO @@@ */
3023 return(0);
3024 } else {
3025 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00003026
Daniel Veillardce244ad2004-11-05 10:03:46 +00003027 if (elem == NULL) return(0);
Daniel Veillard37721922001-05-04 15:21:12 +00003028 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3029 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3030 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3031 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00003032
Daniel Veillard37721922001-05-04 15:21:12 +00003033 if ((attrDecl != NULL) &&
3034 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3035 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3036 return(1);
3037 }
3038 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003039}
3040
3041/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003042 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00003043 * @doc: the document
3044 * @attr: the attribute
3045 *
3046 * Remove the given attribute from the Ref table maintained internally.
3047 *
3048 * Returns -1 if the lookup failed and 0 otherwise
3049 */
3050int
3051xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00003052 xmlListPtr ref_list;
3053 xmlRefTablePtr table;
3054 xmlChar *ID;
3055 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00003056
Daniel Veillard37721922001-05-04 15:21:12 +00003057 if (doc == NULL) return(-1);
3058 if (attr == NULL) return(-1);
3059 table = (xmlRefTablePtr) doc->refs;
3060 if (table == NULL)
3061 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003062
Daniel Veillard37721922001-05-04 15:21:12 +00003063 if (attr == NULL)
3064 return(-1);
3065 ID = xmlNodeListGetString(doc, attr->children, 1);
3066 if (ID == NULL)
3067 return(-1);
3068 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00003069
Daniel Veillard37721922001-05-04 15:21:12 +00003070 if(ref_list == NULL) {
3071 xmlFree(ID);
3072 return (-1);
3073 }
3074 /* At this point, ref_list refers to a list of references which
3075 * have the same key as the supplied attr. Our list of references
3076 * is ordered by reference address and we don't have that information
3077 * here to use when removing. We'll have to walk the list and
3078 * check for a matching attribute, when we find one stop the walk
3079 * and remove the entry.
3080 * The list is ordered by reference, so that means we don't have the
3081 * key. Passing the list and the reference to the walker means we
3082 * will have enough data to be able to remove the entry.
3083 */
3084 target.l = ref_list;
3085 target.ap = attr;
3086
3087 /* Remove the supplied attr from our list */
3088 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00003089
Daniel Veillard37721922001-05-04 15:21:12 +00003090 /*If the list is empty then remove the list entry in the hash */
3091 if (xmlListEmpty(ref_list))
3092 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
3093 xmlFreeRefList);
3094 xmlFree(ID);
3095 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003096}
3097
3098/**
3099 * xmlGetRefs:
3100 * @doc: pointer to the document
3101 * @ID: the ID value
3102 *
3103 * Find the set of references for the supplied ID.
3104 *
3105 * Returns NULL if not found, otherwise node set for the ID.
3106 */
3107xmlListPtr
3108xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00003109 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00003110
Daniel Veillard37721922001-05-04 15:21:12 +00003111 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003112 return(NULL);
3113 }
Owen Taylor3473f882001-02-23 17:55:21 +00003114
Daniel Veillard37721922001-05-04 15:21:12 +00003115 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003116 return(NULL);
3117 }
Owen Taylor3473f882001-02-23 17:55:21 +00003118
Daniel Veillard37721922001-05-04 15:21:12 +00003119 table = (xmlRefTablePtr) doc->refs;
3120 if (table == NULL)
3121 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003122
Daniel Veillard37721922001-05-04 15:21:12 +00003123 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00003124}
3125
3126/************************************************************************
3127 * *
3128 * Routines for validity checking *
3129 * *
3130 ************************************************************************/
3131
3132/**
3133 * xmlGetDtdElementDesc:
3134 * @dtd: a pointer to the DtD to search
3135 * @name: the element name
3136 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003137 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003138 *
3139 * returns the xmlElementPtr if found or NULL
3140 */
3141
3142xmlElementPtr
3143xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3144 xmlElementTablePtr table;
3145 xmlElementPtr cur;
3146 xmlChar *uqname = NULL, *prefix = NULL;
3147
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00003148 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003149 if (dtd->elements == NULL)
3150 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003151 table = (xmlElementTablePtr) dtd->elements;
3152
3153 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003154 if (uqname != NULL)
3155 name = uqname;
3156 cur = xmlHashLookup2(table, name, prefix);
3157 if (prefix != NULL) xmlFree(prefix);
3158 if (uqname != NULL) xmlFree(uqname);
3159 return(cur);
3160}
3161/**
3162 * xmlGetDtdElementDesc2:
3163 * @dtd: a pointer to the DtD to search
3164 * @name: the element name
3165 * @create: create an empty description if not found
3166 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003167 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00003168 *
3169 * returns the xmlElementPtr if found or NULL
3170 */
3171
Daniel Veillard86fd5a72001-12-13 14:55:21 +00003172static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00003173xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3174 xmlElementTablePtr table;
3175 xmlElementPtr cur;
3176 xmlChar *uqname = NULL, *prefix = NULL;
3177
3178 if (dtd == NULL) return(NULL);
3179 if (dtd->elements == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003180 xmlDictPtr dict = NULL;
3181
3182 if (dtd->doc != NULL)
3183 dict = dtd->doc->dict;
3184
Daniel Veillarda10efa82001-04-18 13:09:01 +00003185 if (!create)
3186 return(NULL);
3187 /*
3188 * Create the Element table if needed.
3189 */
3190 table = (xmlElementTablePtr) dtd->elements;
3191 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003192 table = xmlHashCreateDict(0, dict);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003193 dtd->elements = (void *) table;
3194 }
3195 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003196 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003197 return(NULL);
3198 }
3199 }
3200 table = (xmlElementTablePtr) dtd->elements;
3201
3202 uqname = xmlSplitQName2(name, &prefix);
3203 if (uqname != NULL)
3204 name = uqname;
3205 cur = xmlHashLookup2(table, name, prefix);
3206 if ((cur == NULL) && (create)) {
3207 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3208 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003209 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003210 return(NULL);
3211 }
3212 memset(cur, 0, sizeof(xmlElement));
3213 cur->type = XML_ELEMENT_DECL;
3214
3215 /*
3216 * fill the structure.
3217 */
3218 cur->name = xmlStrdup(name);
3219 cur->prefix = xmlStrdup(prefix);
3220 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3221
3222 xmlHashAddEntry2(table, name, prefix, cur);
3223 }
3224 if (prefix != NULL) xmlFree(prefix);
3225 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003226 return(cur);
3227}
3228
3229/**
3230 * xmlGetDtdQElementDesc:
3231 * @dtd: a pointer to the DtD to search
3232 * @name: the element name
3233 * @prefix: the element namespace prefix
3234 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003235 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003236 *
3237 * returns the xmlElementPtr if found or NULL
3238 */
3239
Daniel Veillard48da9102001-08-07 01:10:10 +00003240xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003241xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3242 const xmlChar *prefix) {
3243 xmlElementTablePtr table;
3244
3245 if (dtd == NULL) return(NULL);
3246 if (dtd->elements == NULL) return(NULL);
3247 table = (xmlElementTablePtr) dtd->elements;
3248
3249 return(xmlHashLookup2(table, name, prefix));
3250}
3251
3252/**
3253 * xmlGetDtdAttrDesc:
3254 * @dtd: a pointer to the DtD to search
3255 * @elem: the element name
3256 * @name: the attribute name
3257 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003258 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003259 * this element.
3260 *
3261 * returns the xmlAttributePtr if found or NULL
3262 */
3263
3264xmlAttributePtr
3265xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3266 xmlAttributeTablePtr table;
3267 xmlAttributePtr cur;
3268 xmlChar *uqname = NULL, *prefix = NULL;
3269
3270 if (dtd == NULL) return(NULL);
3271 if (dtd->attributes == NULL) return(NULL);
3272
3273 table = (xmlAttributeTablePtr) dtd->attributes;
3274 if (table == NULL)
3275 return(NULL);
3276
3277 uqname = xmlSplitQName2(name, &prefix);
3278
3279 if (uqname != NULL) {
3280 cur = xmlHashLookup3(table, uqname, prefix, elem);
3281 if (prefix != NULL) xmlFree(prefix);
3282 if (uqname != NULL) xmlFree(uqname);
3283 } else
3284 cur = xmlHashLookup3(table, name, NULL, elem);
3285 return(cur);
3286}
3287
3288/**
3289 * xmlGetDtdQAttrDesc:
3290 * @dtd: a pointer to the DtD to search
3291 * @elem: the element name
3292 * @name: the attribute name
3293 * @prefix: the attribute namespace prefix
3294 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003295 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003296 * this element.
3297 *
3298 * returns the xmlAttributePtr if found or NULL
3299 */
3300
Daniel Veillard48da9102001-08-07 01:10:10 +00003301xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003302xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3303 const xmlChar *prefix) {
3304 xmlAttributeTablePtr table;
3305
3306 if (dtd == NULL) return(NULL);
3307 if (dtd->attributes == NULL) return(NULL);
3308 table = (xmlAttributeTablePtr) dtd->attributes;
3309
3310 return(xmlHashLookup3(table, name, prefix, elem));
3311}
3312
3313/**
3314 * xmlGetDtdNotationDesc:
3315 * @dtd: a pointer to the DtD to search
3316 * @name: the notation name
3317 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003318 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003319 *
3320 * returns the xmlNotationPtr if found or NULL
3321 */
3322
3323xmlNotationPtr
3324xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3325 xmlNotationTablePtr table;
3326
3327 if (dtd == NULL) return(NULL);
3328 if (dtd->notations == NULL) return(NULL);
3329 table = (xmlNotationTablePtr) dtd->notations;
3330
3331 return(xmlHashLookup(table, name));
3332}
3333
Daniel Veillardf54cd532004-02-25 11:52:31 +00003334#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003335/**
3336 * xmlValidateNotationUse:
3337 * @ctxt: the validation context
3338 * @doc: the document
3339 * @notationName: the notation name to check
3340 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003341 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003342 * - [ VC: Notation Declared ]
3343 *
3344 * returns 1 if valid or 0 otherwise
3345 */
3346
3347int
3348xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3349 const xmlChar *notationName) {
3350 xmlNotationPtr notaDecl;
3351 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3352
3353 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3354 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3355 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3356
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003357 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003358 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3359 "NOTATION %s is not declared\n",
3360 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003361 return(0);
3362 }
3363 return(1);
3364}
Daniel Veillardf54cd532004-02-25 11:52:31 +00003365#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003366
3367/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003368 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003369 * @doc: the document
3370 * @name: the element name
3371 *
3372 * Search in the DtDs whether an element accept Mixed content (or ANY)
3373 * basically if it is supposed to accept text childs
3374 *
3375 * returns 0 if no, 1 if yes, and -1 if no element description is available
3376 */
3377
3378int
3379xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3380 xmlElementPtr elemDecl;
3381
3382 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3383
3384 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3385 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3386 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3387 if (elemDecl == NULL) return(-1);
3388 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003389 case XML_ELEMENT_TYPE_UNDEFINED:
3390 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003391 case XML_ELEMENT_TYPE_ELEMENT:
3392 return(0);
3393 case XML_ELEMENT_TYPE_EMPTY:
3394 /*
3395 * return 1 for EMPTY since we want VC error to pop up
3396 * on <empty> </empty> for example
3397 */
3398 case XML_ELEMENT_TYPE_ANY:
3399 case XML_ELEMENT_TYPE_MIXED:
3400 return(1);
3401 }
3402 return(1);
3403}
3404
Daniel Veillard4432df22003-09-28 18:58:27 +00003405#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003406/**
3407 * xmlValidateNameValue:
3408 * @value: an Name value
3409 *
3410 * Validate that the given value match Name production
3411 *
3412 * returns 1 if valid or 0 otherwise
3413 */
3414
Daniel Veillard9b731d72002-04-14 12:56:08 +00003415int
Owen Taylor3473f882001-02-23 17:55:21 +00003416xmlValidateNameValue(const xmlChar *value) {
3417 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003418 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003419
3420 if (value == NULL) return(0);
3421 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003422 val = xmlStringCurrentChar(NULL, cur, &len);
3423 cur += len;
3424 if (!IS_LETTER(val) && (val != '_') &&
3425 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003426 return(0);
3427 }
3428
Daniel Veillardd8224e02002-01-13 15:43:22 +00003429 val = xmlStringCurrentChar(NULL, cur, &len);
3430 cur += len;
3431 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3432 (val == '.') || (val == '-') ||
3433 (val == '_') || (val == ':') ||
3434 (IS_COMBINING(val)) ||
3435 (IS_EXTENDER(val))) {
3436 val = xmlStringCurrentChar(NULL, cur, &len);
3437 cur += len;
3438 }
Owen Taylor3473f882001-02-23 17:55:21 +00003439
Daniel Veillardd8224e02002-01-13 15:43:22 +00003440 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003441
3442 return(1);
3443}
3444
3445/**
3446 * xmlValidateNamesValue:
3447 * @value: an Names value
3448 *
3449 * Validate that the given value match Names production
3450 *
3451 * returns 1 if valid or 0 otherwise
3452 */
3453
Daniel Veillard9b731d72002-04-14 12:56:08 +00003454int
Owen Taylor3473f882001-02-23 17:55:21 +00003455xmlValidateNamesValue(const xmlChar *value) {
3456 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003457 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003458
3459 if (value == NULL) return(0);
3460 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003461 val = xmlStringCurrentChar(NULL, cur, &len);
3462 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003463
Daniel Veillardd8224e02002-01-13 15:43:22 +00003464 if (!IS_LETTER(val) && (val != '_') &&
3465 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003466 return(0);
3467 }
3468
Daniel Veillardd8224e02002-01-13 15:43:22 +00003469 val = xmlStringCurrentChar(NULL, cur, &len);
3470 cur += len;
3471 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3472 (val == '.') || (val == '-') ||
3473 (val == '_') || (val == ':') ||
3474 (IS_COMBINING(val)) ||
3475 (IS_EXTENDER(val))) {
3476 val = xmlStringCurrentChar(NULL, cur, &len);
3477 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003478 }
3479
Daniel Veillard807b4de2004-09-26 14:42:56 +00003480 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3481 while (val == 0x20) {
3482 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003483 val = xmlStringCurrentChar(NULL, cur, &len);
3484 cur += len;
3485 }
3486
3487 if (!IS_LETTER(val) && (val != '_') &&
3488 (val != ':')) {
3489 return(0);
3490 }
3491 val = xmlStringCurrentChar(NULL, cur, &len);
3492 cur += len;
3493
3494 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3495 (val == '.') || (val == '-') ||
3496 (val == '_') || (val == ':') ||
3497 (IS_COMBINING(val)) ||
3498 (IS_EXTENDER(val))) {
3499 val = xmlStringCurrentChar(NULL, cur, &len);
3500 cur += len;
3501 }
3502 }
3503
3504 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003505
3506 return(1);
3507}
3508
3509/**
3510 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003511 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003512 *
3513 * Validate that the given value match Nmtoken production
3514 *
3515 * [ VC: Name Token ]
3516 *
3517 * returns 1 if valid or 0 otherwise
3518 */
3519
Daniel Veillard9b731d72002-04-14 12:56:08 +00003520int
Owen Taylor3473f882001-02-23 17:55:21 +00003521xmlValidateNmtokenValue(const xmlChar *value) {
3522 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003523 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003524
3525 if (value == NULL) return(0);
3526 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003527 val = xmlStringCurrentChar(NULL, cur, &len);
3528 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003529
Daniel Veillardd8224e02002-01-13 15:43:22 +00003530 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3531 (val != '.') && (val != '-') &&
3532 (val != '_') && (val != ':') &&
3533 (!IS_COMBINING(val)) &&
3534 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003535 return(0);
3536
Daniel Veillardd8224e02002-01-13 15:43:22 +00003537 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3538 (val == '.') || (val == '-') ||
3539 (val == '_') || (val == ':') ||
3540 (IS_COMBINING(val)) ||
3541 (IS_EXTENDER(val))) {
3542 val = xmlStringCurrentChar(NULL, cur, &len);
3543 cur += len;
3544 }
Owen Taylor3473f882001-02-23 17:55:21 +00003545
Daniel Veillardd8224e02002-01-13 15:43:22 +00003546 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003547
3548 return(1);
3549}
3550
3551/**
3552 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003553 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003554 *
3555 * Validate that the given value match Nmtokens production
3556 *
3557 * [ VC: Name Token ]
3558 *
3559 * returns 1 if valid or 0 otherwise
3560 */
3561
Daniel Veillard9b731d72002-04-14 12:56:08 +00003562int
Owen Taylor3473f882001-02-23 17:55:21 +00003563xmlValidateNmtokensValue(const xmlChar *value) {
3564 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003565 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003566
3567 if (value == NULL) return(0);
3568 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003569 val = xmlStringCurrentChar(NULL, cur, &len);
3570 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003571
Daniel Veillardd8224e02002-01-13 15:43:22 +00003572 while (IS_BLANK(val)) {
3573 val = xmlStringCurrentChar(NULL, cur, &len);
3574 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003575 }
3576
Daniel Veillardd8224e02002-01-13 15:43:22 +00003577 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3578 (val != '.') && (val != '-') &&
3579 (val != '_') && (val != ':') &&
3580 (!IS_COMBINING(val)) &&
3581 (!IS_EXTENDER(val)))
3582 return(0);
3583
3584 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3585 (val == '.') || (val == '-') ||
3586 (val == '_') || (val == ':') ||
3587 (IS_COMBINING(val)) ||
3588 (IS_EXTENDER(val))) {
3589 val = xmlStringCurrentChar(NULL, cur, &len);
3590 cur += len;
3591 }
3592
Daniel Veillard807b4de2004-09-26 14:42:56 +00003593 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3594 while (val == 0x20) {
3595 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003596 val = xmlStringCurrentChar(NULL, cur, &len);
3597 cur += len;
3598 }
3599 if (val == 0) return(1);
3600
3601 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3602 (val != '.') && (val != '-') &&
3603 (val != '_') && (val != ':') &&
3604 (!IS_COMBINING(val)) &&
3605 (!IS_EXTENDER(val)))
3606 return(0);
3607
3608 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3609 (val == '.') || (val == '-') ||
3610 (val == '_') || (val == ':') ||
3611 (IS_COMBINING(val)) ||
3612 (IS_EXTENDER(val))) {
3613 val = xmlStringCurrentChar(NULL, cur, &len);
3614 cur += len;
3615 }
3616 }
3617
3618 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003619
3620 return(1);
3621}
3622
3623/**
3624 * xmlValidateNotationDecl:
3625 * @ctxt: the validation context
3626 * @doc: a document instance
3627 * @nota: a notation definition
3628 *
3629 * Try to validate a single notation definition
3630 * basically it does the following checks as described by the
3631 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003632 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003633 * But this function get called anyway ...
3634 *
3635 * returns 1 if valid or 0 otherwise
3636 */
3637
3638int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003639xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3640 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003641 int ret = 1;
3642
3643 return(ret);
3644}
3645
3646/**
3647 * xmlValidateAttributeValue:
3648 * @type: an attribute type
3649 * @value: an attribute value
3650 *
3651 * Validate that the given attribute value match the proper production
3652 *
3653 * [ VC: ID ]
3654 * Values of type ID must match the Name production....
3655 *
3656 * [ VC: IDREF ]
3657 * Values of type IDREF must match the Name production, and values
3658 * of type IDREFS must match Names ...
3659 *
3660 * [ VC: Entity Name ]
3661 * Values of type ENTITY must match the Name production, values
3662 * of type ENTITIES must match Names ...
3663 *
3664 * [ VC: Name Token ]
3665 * Values of type NMTOKEN must match the Nmtoken production; values
3666 * of type NMTOKENS must match Nmtokens.
3667 *
3668 * returns 1 if valid or 0 otherwise
3669 */
3670
3671int
3672xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3673 switch (type) {
3674 case XML_ATTRIBUTE_ENTITIES:
3675 case XML_ATTRIBUTE_IDREFS:
3676 return(xmlValidateNamesValue(value));
3677 case XML_ATTRIBUTE_ENTITY:
3678 case XML_ATTRIBUTE_IDREF:
3679 case XML_ATTRIBUTE_ID:
3680 case XML_ATTRIBUTE_NOTATION:
3681 return(xmlValidateNameValue(value));
3682 case XML_ATTRIBUTE_NMTOKENS:
3683 case XML_ATTRIBUTE_ENUMERATION:
3684 return(xmlValidateNmtokensValue(value));
3685 case XML_ATTRIBUTE_NMTOKEN:
3686 return(xmlValidateNmtokenValue(value));
3687 case XML_ATTRIBUTE_CDATA:
3688 break;
3689 }
3690 return(1);
3691}
3692
3693/**
3694 * xmlValidateAttributeValue2:
3695 * @ctxt: the validation context
3696 * @doc: the document
3697 * @name: the attribute name (used for error reporting only)
3698 * @type: the attribute type
3699 * @value: the attribute value
3700 *
3701 * Validate that the given attribute value match a given type.
3702 * This typically cannot be done before having finished parsing
3703 * the subsets.
3704 *
3705 * [ VC: IDREF ]
3706 * Values of type IDREF must match one of the declared IDs
3707 * Values of type IDREFS must match a sequence of the declared IDs
3708 * each Name must match the value of an ID attribute on some element
3709 * in the XML document; i.e. IDREF values must match the value of
3710 * some ID attribute
3711 *
3712 * [ VC: Entity Name ]
3713 * Values of type ENTITY must match one declared entity
3714 * Values of type ENTITIES must match a sequence of declared entities
3715 *
3716 * [ VC: Notation Attributes ]
3717 * all notation names in the declaration must be declared.
3718 *
3719 * returns 1 if valid or 0 otherwise
3720 */
3721
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003722static int
Owen Taylor3473f882001-02-23 17:55:21 +00003723xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3724 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3725 int ret = 1;
3726 switch (type) {
3727 case XML_ATTRIBUTE_IDREFS:
3728 case XML_ATTRIBUTE_IDREF:
3729 case XML_ATTRIBUTE_ID:
3730 case XML_ATTRIBUTE_NMTOKENS:
3731 case XML_ATTRIBUTE_ENUMERATION:
3732 case XML_ATTRIBUTE_NMTOKEN:
3733 case XML_ATTRIBUTE_CDATA:
3734 break;
3735 case XML_ATTRIBUTE_ENTITY: {
3736 xmlEntityPtr ent;
3737
3738 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003739 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003740 if ((ent == NULL) && (doc->standalone == 1)) {
3741 doc->standalone = 0;
3742 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003743 }
Owen Taylor3473f882001-02-23 17:55:21 +00003744 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003745 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3746 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003747 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003748 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003749 ret = 0;
3750 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003751 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3752 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003753 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003754 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003755 ret = 0;
3756 }
3757 break;
3758 }
3759 case XML_ATTRIBUTE_ENTITIES: {
3760 xmlChar *dup, *nam = NULL, *cur, save;
3761 xmlEntityPtr ent;
3762
3763 dup = xmlStrdup(value);
3764 if (dup == NULL)
3765 return(0);
3766 cur = dup;
3767 while (*cur != 0) {
3768 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003769 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003770 save = *cur;
3771 *cur = 0;
3772 ent = xmlGetDocEntity(doc, nam);
3773 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003774 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3775 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003776 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003777 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003778 ret = 0;
3779 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003780 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3781 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003782 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003783 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003784 ret = 0;
3785 }
3786 if (save == 0)
3787 break;
3788 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003789 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003790 }
3791 xmlFree(dup);
3792 break;
3793 }
3794 case XML_ATTRIBUTE_NOTATION: {
3795 xmlNotationPtr nota;
3796
3797 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3798 if ((nota == NULL) && (doc->extSubset != NULL))
3799 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3800
3801 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003802 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3803 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003804 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003805 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003806 ret = 0;
3807 }
3808 break;
3809 }
3810 }
3811 return(ret);
3812}
3813
3814/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003815 * xmlValidCtxtNormalizeAttributeValue:
3816 * @ctxt: the validation context
3817 * @doc: the document
3818 * @elem: the parent
3819 * @name: the attribute name
3820 * @value: the attribute value
3821 * @ctxt: the validation context or NULL
3822 *
3823 * Does the validation related extra step of the normalization of attribute
3824 * values:
3825 *
3826 * If the declared value is not CDATA, then the XML processor must further
3827 * process the normalized attribute value by discarding any leading and
3828 * trailing space (#x20) characters, and by replacing sequences of space
3829 * (#x20) characters by single space (#x20) character.
3830 *
3831 * Also check VC: Standalone Document Declaration in P32, and update
3832 * ctxt->valid accordingly
3833 *
3834 * returns a new normalized string if normalization is needed, NULL otherwise
3835 * the caller must free the returned value.
3836 */
3837
3838xmlChar *
3839xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3840 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3841 xmlChar *ret, *dst;
3842 const xmlChar *src;
3843 xmlAttributePtr attrDecl = NULL;
3844 int extsubset = 0;
3845
3846 if (doc == NULL) return(NULL);
3847 if (elem == NULL) return(NULL);
3848 if (name == NULL) return(NULL);
3849 if (value == NULL) return(NULL);
3850
3851 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003852 xmlChar fn[50];
3853 xmlChar *fullname;
3854
3855 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3856 if (fullname == NULL)
3857 return(0);
3858 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003859 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003860 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003861 if (attrDecl != NULL)
3862 extsubset = 1;
3863 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003864 if ((fullname != fn) && (fullname != elem->name))
3865 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003866 }
3867 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3868 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3869 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3870 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3871 if (attrDecl != NULL)
3872 extsubset = 1;
3873 }
3874
3875 if (attrDecl == NULL)
3876 return(NULL);
3877 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3878 return(NULL);
3879
3880 ret = xmlStrdup(value);
3881 if (ret == NULL)
3882 return(NULL);
3883 src = value;
3884 dst = ret;
3885 while (*src == 0x20) src++;
3886 while (*src != 0) {
3887 if (*src == 0x20) {
3888 while (*src == 0x20) src++;
3889 if (*src != 0)
3890 *dst++ = 0x20;
3891 } else {
3892 *dst++ = *src++;
3893 }
3894 }
3895 *dst = 0;
3896 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003897 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003898"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003899 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003900 ctxt->valid = 0;
3901 }
3902 return(ret);
3903}
3904
3905/**
Owen Taylor3473f882001-02-23 17:55:21 +00003906 * xmlValidNormalizeAttributeValue:
3907 * @doc: the document
3908 * @elem: the parent
3909 * @name: the attribute name
3910 * @value: the attribute value
3911 *
3912 * Does the validation related extra step of the normalization of attribute
3913 * values:
3914 *
3915 * If the declared value is not CDATA, then the XML processor must further
3916 * process the normalized attribute value by discarding any leading and
3917 * trailing space (#x20) characters, and by replacing sequences of space
3918 * (#x20) characters by single space (#x20) character.
3919 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003920 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003921 * the caller must free the returned value.
3922 */
3923
3924xmlChar *
3925xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3926 const xmlChar *name, const xmlChar *value) {
3927 xmlChar *ret, *dst;
3928 const xmlChar *src;
3929 xmlAttributePtr attrDecl = NULL;
3930
3931 if (doc == NULL) return(NULL);
3932 if (elem == NULL) return(NULL);
3933 if (name == NULL) return(NULL);
3934 if (value == NULL) return(NULL);
3935
3936 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003937 xmlChar fn[50];
3938 xmlChar *fullname;
3939
3940 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3941 if (fullname == NULL)
3942 return(0);
3943 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003944 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003945 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3946 if ((fullname != fn) && (fullname != elem->name))
3947 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003948 }
3949 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3950 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3951 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3952
3953 if (attrDecl == NULL)
3954 return(NULL);
3955 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3956 return(NULL);
3957
3958 ret = xmlStrdup(value);
3959 if (ret == NULL)
3960 return(NULL);
3961 src = value;
3962 dst = ret;
3963 while (*src == 0x20) src++;
3964 while (*src != 0) {
3965 if (*src == 0x20) {
3966 while (*src == 0x20) src++;
3967 if (*src != 0)
3968 *dst++ = 0x20;
3969 } else {
3970 *dst++ = *src++;
3971 }
3972 }
3973 *dst = 0;
3974 return(ret);
3975}
3976
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003977static void
Owen Taylor3473f882001-02-23 17:55:21 +00003978xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003979 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003980 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3981}
3982
3983/**
3984 * xmlValidateAttributeDecl:
3985 * @ctxt: the validation context
3986 * @doc: a document instance
3987 * @attr: an attribute definition
3988 *
3989 * Try to validate a single attribute definition
3990 * basically it does the following checks as described by the
3991 * XML-1.0 recommendation:
3992 * - [ VC: Attribute Default Legal ]
3993 * - [ VC: Enumeration ]
3994 * - [ VC: ID Attribute Default ]
3995 *
3996 * The ID/IDREF uniqueness and matching are done separately
3997 *
3998 * returns 1 if valid or 0 otherwise
3999 */
4000
4001int
4002xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4003 xmlAttributePtr attr) {
4004 int ret = 1;
4005 int val;
4006 CHECK_DTD;
4007 if(attr == NULL) return(1);
4008
4009 /* Attribute Default Legal */
4010 /* Enumeration */
4011 if (attr->defaultValue != NULL) {
4012 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
4013 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004014 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004015 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004016 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004017 }
4018 ret &= val;
4019 }
4020
4021 /* ID Attribute Default */
4022 if ((attr->atype == XML_ATTRIBUTE_ID)&&
4023 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4024 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004025 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004026 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004027 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004028 ret = 0;
4029 }
4030
4031 /* One ID per Element Type */
4032 if (attr->atype == XML_ATTRIBUTE_ID) {
4033 int nbId;
4034
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004035 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00004036 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4037 attr->elem);
4038 if (elem != NULL) {
4039 nbId = xmlScanIDAttributeDecl(NULL, elem);
4040 } else {
4041 xmlAttributeTablePtr table;
4042
4043 /*
4044 * The attribute may be declared in the internal subset and the
4045 * element in the external subset.
4046 */
4047 nbId = 0;
4048 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4049 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
4050 xmlValidateAttributeIdCallback, &nbId);
4051 }
4052 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004053
4054 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004055 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4056 attr->elem, nbId, attr->name);
4057 } else if (doc->extSubset != NULL) {
4058 int extId = 0;
4059 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4060 if (elem != NULL) {
4061 extId = xmlScanIDAttributeDecl(NULL, elem);
4062 }
4063 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004064 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004065 "Element %s has %d ID attribute defined in the external subset : %s\n",
4066 attr->elem, extId, attr->name);
4067 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004068 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004069"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004070 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004071 }
4072 }
4073 }
4074
4075 /* Validity Constraint: Enumeration */
4076 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4077 xmlEnumerationPtr tree = attr->tree;
4078 while (tree != NULL) {
4079 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4080 tree = tree->next;
4081 }
4082 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004083 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004084"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004085 attr->defaultValue, attr->name, attr->elem);
4086 ret = 0;
4087 }
4088 }
4089
4090 return(ret);
4091}
4092
4093/**
4094 * xmlValidateElementDecl:
4095 * @ctxt: the validation context
4096 * @doc: a document instance
4097 * @elem: an element definition
4098 *
4099 * Try to validate a single element definition
4100 * basically it does the following checks as described by the
4101 * XML-1.0 recommendation:
4102 * - [ VC: One ID per Element Type ]
4103 * - [ VC: No Duplicate Types ]
4104 * - [ VC: Unique Element Type Declaration ]
4105 *
4106 * returns 1 if valid or 0 otherwise
4107 */
4108
4109int
4110xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4111 xmlElementPtr elem) {
4112 int ret = 1;
4113 xmlElementPtr tst;
4114
4115 CHECK_DTD;
4116
4117 if (elem == NULL) return(1);
4118
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004119#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00004120#ifdef LIBXML_REGEXP_ENABLED
4121 /* Build the regexp associated to the content model */
4122 ret = xmlValidBuildContentModel(ctxt, elem);
4123#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004124#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00004125
Owen Taylor3473f882001-02-23 17:55:21 +00004126 /* No Duplicate Types */
4127 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4128 xmlElementContentPtr cur, next;
4129 const xmlChar *name;
4130
4131 cur = elem->content;
4132 while (cur != NULL) {
4133 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4134 if (cur->c1 == NULL) break;
4135 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4136 name = cur->c1->name;
4137 next = cur->c2;
4138 while (next != NULL) {
4139 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00004140 if ((xmlStrEqual(next->name, name)) &&
4141 (xmlStrEqual(next->prefix, cur->prefix))) {
4142 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004143 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00004144 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004145 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004146 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004147 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004148 "Definition of %s has duplicate references of %s:%s\n",
4149 elem->name, cur->prefix, name);
4150 }
Owen Taylor3473f882001-02-23 17:55:21 +00004151 ret = 0;
4152 }
4153 break;
4154 }
4155 if (next->c1 == NULL) break;
4156 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00004157 if ((xmlStrEqual(next->c1->name, name)) &&
4158 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
4159 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004160 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004161 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004162 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004163 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004164 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004165 "Definition of %s has duplicate references to %s:%s\n",
4166 elem->name, cur->prefix, name);
4167 }
Owen Taylor3473f882001-02-23 17:55:21 +00004168 ret = 0;
4169 }
4170 next = next->c2;
4171 }
4172 }
4173 cur = cur->c2;
4174 }
4175 }
4176
4177 /* VC: Unique Element Type Declaration */
4178 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004179 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004180 ((tst->prefix == elem->prefix) ||
4181 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004182 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004183 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4184 "Redefinition of element %s\n",
4185 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004186 ret = 0;
4187 }
4188 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004189 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004190 ((tst->prefix == elem->prefix) ||
4191 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004192 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004193 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4194 "Redefinition of element %s\n",
4195 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004196 ret = 0;
4197 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004198 /* One ID per Element Type
4199 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004200 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4201 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004202 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004203 return(ret);
4204}
4205
4206/**
4207 * xmlValidateOneAttribute:
4208 * @ctxt: the validation context
4209 * @doc: a document instance
4210 * @elem: an element instance
4211 * @attr: an attribute instance
4212 * @value: the attribute value (without entities processing)
4213 *
4214 * Try to validate a single attribute for an element
4215 * basically it does the following checks as described by the
4216 * XML-1.0 recommendation:
4217 * - [ VC: Attribute Value Type ]
4218 * - [ VC: Fixed Attribute Default ]
4219 * - [ VC: Entity Name ]
4220 * - [ VC: Name Token ]
4221 * - [ VC: ID ]
4222 * - [ VC: IDREF ]
4223 * - [ VC: Entity Name ]
4224 * - [ VC: Notation Attributes ]
4225 *
4226 * The ID/IDREF uniqueness and matching are done separately
4227 *
4228 * returns 1 if valid or 0 otherwise
4229 */
4230
4231int
4232xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004233 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4234{
Owen Taylor3473f882001-02-23 17:55:21 +00004235 xmlAttributePtr attrDecl = NULL;
4236 int val;
4237 int ret = 1;
4238
4239 CHECK_DTD;
4240 if ((elem == NULL) || (elem->name == NULL)) return(0);
4241 if ((attr == NULL) || (attr->name == NULL)) return(0);
4242
4243 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004244 xmlChar fn[50];
4245 xmlChar *fullname;
4246
4247 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4248 if (fullname == NULL)
4249 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004250 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004251 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004252 attr->name, attr->ns->prefix);
4253 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004254 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004255 attr->name, attr->ns->prefix);
4256 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004257 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004258 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4259 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004260 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004261 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004262 if ((fullname != fn) && (fullname != elem->name))
4263 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004264 }
4265 if (attrDecl == NULL) {
4266 if (attr->ns != NULL) {
4267 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4268 attr->name, attr->ns->prefix);
4269 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4270 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4271 attr->name, attr->ns->prefix);
4272 } else {
4273 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4274 elem->name, attr->name);
4275 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4276 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4277 elem->name, attr->name);
4278 }
4279 }
4280
4281
4282 /* Validity Constraint: Attribute Value Type */
4283 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004284 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004285 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004286 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004287 return(0);
4288 }
4289 attr->atype = attrDecl->atype;
4290
4291 val = xmlValidateAttributeValue(attrDecl->atype, value);
4292 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004293 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004294 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004295 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004296 ret = 0;
4297 }
4298
4299 /* Validity constraint: Fixed Attribute Default */
4300 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4301 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004302 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004303 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004304 attr->name, elem->name, attrDecl->defaultValue);
4305 ret = 0;
4306 }
4307 }
4308
4309 /* Validity Constraint: ID uniqueness */
4310 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4311 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4312 ret = 0;
4313 }
4314
4315 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4316 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4317 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4318 ret = 0;
4319 }
4320
4321 /* Validity Constraint: Notation Attributes */
4322 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4323 xmlEnumerationPtr tree = attrDecl->tree;
4324 xmlNotationPtr nota;
4325
4326 /* First check that the given NOTATION was declared */
4327 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4328 if (nota == NULL)
4329 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4330
4331 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004332 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004333 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004334 value, attr->name, elem->name);
4335 ret = 0;
4336 }
4337
4338 /* Second, verify that it's among the list */
4339 while (tree != NULL) {
4340 if (xmlStrEqual(tree->name, value)) break;
4341 tree = tree->next;
4342 }
4343 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004344 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004345"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004346 value, attr->name, elem->name);
4347 ret = 0;
4348 }
4349 }
4350
4351 /* Validity Constraint: Enumeration */
4352 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4353 xmlEnumerationPtr tree = attrDecl->tree;
4354 while (tree != NULL) {
4355 if (xmlStrEqual(tree->name, value)) break;
4356 tree = tree->next;
4357 }
4358 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004359 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004360 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004361 value, attr->name, elem->name);
4362 ret = 0;
4363 }
4364 }
4365
4366 /* Fixed Attribute Default */
4367 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4368 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004369 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004370 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004371 attr->name, elem->name, attrDecl->defaultValue);
4372 ret = 0;
4373 }
4374
4375 /* Extra check for the attribute value */
4376 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4377 attrDecl->atype, value);
4378
4379 return(ret);
4380}
4381
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004382/**
4383 * xmlValidateOneNamespace:
4384 * @ctxt: the validation context
4385 * @doc: a document instance
4386 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004387 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004388 * @ns: an namespace declaration instance
4389 * @value: the attribute value (without entities processing)
4390 *
4391 * Try to validate a single namespace declaration for an element
4392 * basically it does the following checks as described by the
4393 * XML-1.0 recommendation:
4394 * - [ VC: Attribute Value Type ]
4395 * - [ VC: Fixed Attribute Default ]
4396 * - [ VC: Entity Name ]
4397 * - [ VC: Name Token ]
4398 * - [ VC: ID ]
4399 * - [ VC: IDREF ]
4400 * - [ VC: Entity Name ]
4401 * - [ VC: Notation Attributes ]
4402 *
4403 * The ID/IDREF uniqueness and matching are done separately
4404 *
4405 * returns 1 if valid or 0 otherwise
4406 */
4407
4408int
4409xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4410xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4411 /* xmlElementPtr elemDecl; */
4412 xmlAttributePtr attrDecl = NULL;
4413 int val;
4414 int ret = 1;
4415
4416 CHECK_DTD;
4417 if ((elem == NULL) || (elem->name == NULL)) return(0);
4418 if ((ns == NULL) || (ns->href == NULL)) return(0);
4419
4420 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004421 xmlChar fn[50];
4422 xmlChar *fullname;
4423
4424 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4425 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004426 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004427 return(0);
4428 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004429 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004430 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004431 ns->prefix, BAD_CAST "xmlns");
4432 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004433 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004434 ns->prefix, BAD_CAST "xmlns");
4435 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004436 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004437 BAD_CAST "xmlns");
4438 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004439 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004440 BAD_CAST "xmlns");
4441 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004442 if ((fullname != fn) && (fullname != elem->name))
4443 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004444 }
4445 if (attrDecl == NULL) {
4446 if (ns->prefix != NULL) {
4447 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4448 ns->prefix, BAD_CAST "xmlns");
4449 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4450 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4451 ns->prefix, BAD_CAST "xmlns");
4452 } else {
4453 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4454 elem->name, BAD_CAST "xmlns");
4455 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4456 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4457 elem->name, BAD_CAST "xmlns");
4458 }
4459 }
4460
4461
4462 /* Validity Constraint: Attribute Value Type */
4463 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004464 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004465 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004466 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004467 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004468 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004469 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004470 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004471 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004472 }
4473 return(0);
4474 }
4475
4476 val = xmlValidateAttributeValue(attrDecl->atype, value);
4477 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004478 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004479 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004480 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004481 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004482 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004483 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004484 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004485 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004486 }
4487 ret = 0;
4488 }
4489
4490 /* Validity constraint: Fixed Attribute Default */
4491 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4492 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004493 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004494 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004495 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4496 ns->prefix, elem->name, attrDecl->defaultValue);
4497 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004498 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004499 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004500 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004501 }
4502 ret = 0;
4503 }
4504 }
4505
4506 /* Validity Constraint: ID uniqueness */
4507 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4508 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4509 ret = 0;
4510 }
4511
4512 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4513 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4514 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4515 ret = 0;
4516 }
4517
4518 /* Validity Constraint: Notation Attributes */
4519 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4520 xmlEnumerationPtr tree = attrDecl->tree;
4521 xmlNotationPtr nota;
4522
4523 /* First check that the given NOTATION was declared */
4524 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4525 if (nota == NULL)
4526 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4527
4528 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004529 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004530 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004531 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4532 value, ns->prefix, elem->name);
4533 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004534 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004535 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004536 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004537 }
4538 ret = 0;
4539 }
4540
4541 /* Second, verify that it's among the list */
4542 while (tree != NULL) {
4543 if (xmlStrEqual(tree->name, value)) break;
4544 tree = tree->next;
4545 }
4546 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004547 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004548 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004549"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4550 value, ns->prefix, elem->name);
4551 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004552 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004553"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004554 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004555 }
4556 ret = 0;
4557 }
4558 }
4559
4560 /* Validity Constraint: Enumeration */
4561 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4562 xmlEnumerationPtr tree = attrDecl->tree;
4563 while (tree != NULL) {
4564 if (xmlStrEqual(tree->name, value)) break;
4565 tree = tree->next;
4566 }
4567 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004568 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004569 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004570"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4571 value, ns->prefix, elem->name);
4572 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004573 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004574"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004575 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004576 }
4577 ret = 0;
4578 }
4579 }
4580
4581 /* Fixed Attribute Default */
4582 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4583 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004584 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004585 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004586 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4587 ns->prefix, elem->name, attrDecl->defaultValue);
4588 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004589 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004590 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004591 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004592 }
4593 ret = 0;
4594 }
4595
4596 /* Extra check for the attribute value */
4597 if (ns->prefix != NULL) {
4598 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4599 attrDecl->atype, value);
4600 } else {
4601 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4602 attrDecl->atype, value);
4603 }
4604
4605 return(ret);
4606}
4607
Daniel Veillard118aed72002-09-24 14:13:13 +00004608#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004609/**
4610 * xmlValidateSkipIgnorable:
4611 * @ctxt: the validation context
4612 * @child: the child list
4613 *
4614 * Skip ignorable elements w.r.t. the validation process
4615 *
4616 * returns the first element to consider for validation of the content model
4617 */
4618
4619static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004620xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004621 while (child != NULL) {
4622 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004623 /* These things are ignored (skipped) during validation. */
4624 case XML_PI_NODE:
4625 case XML_COMMENT_NODE:
4626 case XML_XINCLUDE_START:
4627 case XML_XINCLUDE_END:
4628 child = child->next;
4629 break;
4630 case XML_TEXT_NODE:
4631 if (xmlIsBlankNode(child))
4632 child = child->next;
4633 else
4634 return(child);
4635 break;
4636 /* keep current node */
4637 default:
4638 return(child);
4639 }
4640 }
4641 return(child);
4642}
4643
4644/**
4645 * xmlValidateElementType:
4646 * @ctxt: the validation context
4647 *
4648 * Try to validate the content model of an element internal function
4649 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004650 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4651 * reference is found and -3 if the validation succeeded but
4652 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004653 */
4654
4655static int
4656xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004657 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004658 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004659
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004660 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004661 if ((NODE == NULL) && (CONT == NULL))
4662 return(1);
4663 if ((NODE == NULL) &&
4664 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4665 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4666 return(1);
4667 }
4668 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004669 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004670 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004671
4672 /*
4673 * We arrive here when more states need to be examined
4674 */
4675cont:
4676
4677 /*
4678 * We just recovered from a rollback generated by a possible
4679 * epsilon transition, go directly to the analysis phase
4680 */
4681 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004682 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004683 DEBUG_VALID_STATE(NODE, CONT)
4684 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004685 goto analyze;
4686 }
4687
4688 DEBUG_VALID_STATE(NODE, CONT)
4689 /*
4690 * we may have to save a backup state here. This is the equivalent
4691 * of handling epsilon transition in NFAs.
4692 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004693 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004694 ((CONT->parent == NULL) ||
4695 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004696 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004697 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004698 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004699 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004700 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4701 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004702 }
4703
4704
4705 /*
4706 * Check first if the content matches
4707 */
4708 switch (CONT->type) {
4709 case XML_ELEMENT_CONTENT_PCDATA:
4710 if (NODE == NULL) {
4711 DEBUG_VALID_MSG("pcdata failed no node");
4712 ret = 0;
4713 break;
4714 }
4715 if (NODE->type == XML_TEXT_NODE) {
4716 DEBUG_VALID_MSG("pcdata found, skip to next");
4717 /*
4718 * go to next element in the content model
4719 * skipping ignorable elems
4720 */
4721 do {
4722 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004723 NODE = xmlValidateSkipIgnorable(NODE);
4724 if ((NODE != NULL) &&
4725 (NODE->type == XML_ENTITY_REF_NODE))
4726 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004727 } while ((NODE != NULL) &&
4728 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004729 (NODE->type != XML_TEXT_NODE) &&
4730 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004731 ret = 1;
4732 break;
4733 } else {
4734 DEBUG_VALID_MSG("pcdata failed");
4735 ret = 0;
4736 break;
4737 }
4738 break;
4739 case XML_ELEMENT_CONTENT_ELEMENT:
4740 if (NODE == NULL) {
4741 DEBUG_VALID_MSG("element failed no node");
4742 ret = 0;
4743 break;
4744 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004745 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4746 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004747 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004748 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4749 ret = (CONT->prefix == NULL);
4750 } else if (CONT->prefix == NULL) {
4751 ret = 0;
4752 } else {
4753 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4754 }
4755 }
4756 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004757 DEBUG_VALID_MSG("element found, skip to next");
4758 /*
4759 * go to next element in the content model
4760 * skipping ignorable elems
4761 */
4762 do {
4763 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004764 NODE = xmlValidateSkipIgnorable(NODE);
4765 if ((NODE != NULL) &&
4766 (NODE->type == XML_ENTITY_REF_NODE))
4767 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004768 } while ((NODE != NULL) &&
4769 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004770 (NODE->type != XML_TEXT_NODE) &&
4771 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004772 } else {
4773 DEBUG_VALID_MSG("element failed");
4774 ret = 0;
4775 break;
4776 }
4777 break;
4778 case XML_ELEMENT_CONTENT_OR:
4779 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004780 * Small optimization.
4781 */
4782 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4783 if ((NODE == NULL) ||
4784 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4785 DEPTH++;
4786 CONT = CONT->c2;
4787 goto cont;
4788 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004789 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4790 ret = (CONT->c1->prefix == NULL);
4791 } else if (CONT->c1->prefix == NULL) {
4792 ret = 0;
4793 } else {
4794 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4795 }
4796 if (ret == 0) {
4797 DEPTH++;
4798 CONT = CONT->c2;
4799 goto cont;
4800 }
Daniel Veillard85349052001-04-20 13:48:21 +00004801 }
4802
4803 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004804 * save the second branch 'or' branch
4805 */
4806 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004807 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4808 OCCURS, ROLLBACK_OR) < 0)
4809 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004810 DEPTH++;
4811 CONT = CONT->c1;
4812 goto cont;
4813 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004814 /*
4815 * Small optimization.
4816 */
4817 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4818 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4819 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4820 if ((NODE == NULL) ||
4821 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4822 DEPTH++;
4823 CONT = CONT->c2;
4824 goto cont;
4825 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004826 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4827 ret = (CONT->c1->prefix == NULL);
4828 } else if (CONT->c1->prefix == NULL) {
4829 ret = 0;
4830 } else {
4831 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4832 }
4833 if (ret == 0) {
4834 DEPTH++;
4835 CONT = CONT->c2;
4836 goto cont;
4837 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004838 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004839 DEPTH++;
4840 CONT = CONT->c1;
4841 goto cont;
4842 }
4843
4844 /*
4845 * At this point handle going up in the tree
4846 */
4847 if (ret == -1) {
4848 DEBUG_VALID_MSG("error found returning");
4849 return(ret);
4850 }
4851analyze:
4852 while (CONT != NULL) {
4853 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004854 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004855 * this level.
4856 */
4857 if (ret == 0) {
4858 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004859 xmlNodePtr cur;
4860
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004861 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004862 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004863 DEBUG_VALID_MSG("Once branch failed, rollback");
4864 if (vstateVPop(ctxt) < 0 ) {
4865 DEBUG_VALID_MSG("exhaustion, failed");
4866 return(0);
4867 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004868 if (cur != ctxt->vstate->node)
4869 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004870 goto cont;
4871 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004872 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004873 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004874 DEBUG_VALID_MSG("Plus branch failed, rollback");
4875 if (vstateVPop(ctxt) < 0 ) {
4876 DEBUG_VALID_MSG("exhaustion, failed");
4877 return(0);
4878 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004879 if (cur != ctxt->vstate->node)
4880 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004881 goto cont;
4882 }
4883 DEBUG_VALID_MSG("Plus branch found");
4884 ret = 1;
4885 break;
4886 case XML_ELEMENT_CONTENT_MULT:
4887#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004888 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004889 DEBUG_VALID_MSG("Mult branch failed");
4890 } else {
4891 DEBUG_VALID_MSG("Mult branch found");
4892 }
4893#endif
4894 ret = 1;
4895 break;
4896 case XML_ELEMENT_CONTENT_OPT:
4897 DEBUG_VALID_MSG("Option branch failed");
4898 ret = 1;
4899 break;
4900 }
4901 } else {
4902 switch (CONT->ocur) {
4903 case XML_ELEMENT_CONTENT_OPT:
4904 DEBUG_VALID_MSG("Option branch succeeded");
4905 ret = 1;
4906 break;
4907 case XML_ELEMENT_CONTENT_ONCE:
4908 DEBUG_VALID_MSG("Once branch succeeded");
4909 ret = 1;
4910 break;
4911 case XML_ELEMENT_CONTENT_PLUS:
4912 if (STATE == ROLLBACK_PARENT) {
4913 DEBUG_VALID_MSG("Plus branch rollback");
4914 ret = 1;
4915 break;
4916 }
4917 if (NODE == NULL) {
4918 DEBUG_VALID_MSG("Plus branch exhausted");
4919 ret = 1;
4920 break;
4921 }
4922 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004923 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004924 goto cont;
4925 case XML_ELEMENT_CONTENT_MULT:
4926 if (STATE == ROLLBACK_PARENT) {
4927 DEBUG_VALID_MSG("Mult branch rollback");
4928 ret = 1;
4929 break;
4930 }
4931 if (NODE == NULL) {
4932 DEBUG_VALID_MSG("Mult branch exhausted");
4933 ret = 1;
4934 break;
4935 }
4936 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004937 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004938 goto cont;
4939 }
4940 }
4941 STATE = 0;
4942
4943 /*
4944 * Then act accordingly at the parent level
4945 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004946 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004947 if (CONT->parent == NULL)
4948 break;
4949
4950 switch (CONT->parent->type) {
4951 case XML_ELEMENT_CONTENT_PCDATA:
4952 DEBUG_VALID_MSG("Error: parent pcdata");
4953 return(-1);
4954 case XML_ELEMENT_CONTENT_ELEMENT:
4955 DEBUG_VALID_MSG("Error: parent element");
4956 return(-1);
4957 case XML_ELEMENT_CONTENT_OR:
4958 if (ret == 1) {
4959 DEBUG_VALID_MSG("Or succeeded");
4960 CONT = CONT->parent;
4961 DEPTH--;
4962 } else {
4963 DEBUG_VALID_MSG("Or failed");
4964 CONT = CONT->parent;
4965 DEPTH--;
4966 }
4967 break;
4968 case XML_ELEMENT_CONTENT_SEQ:
4969 if (ret == 0) {
4970 DEBUG_VALID_MSG("Sequence failed");
4971 CONT = CONT->parent;
4972 DEPTH--;
4973 } else if (CONT == CONT->parent->c1) {
4974 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4975 CONT = CONT->parent->c2;
4976 goto cont;
4977 } else {
4978 DEBUG_VALID_MSG("Sequence succeeded");
4979 CONT = CONT->parent;
4980 DEPTH--;
4981 }
4982 }
4983 }
4984 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004985 xmlNodePtr cur;
4986
4987 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004988 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4989 if (vstateVPop(ctxt) < 0 ) {
4990 DEBUG_VALID_MSG("exhaustion, failed");
4991 return(0);
4992 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004993 if (cur != ctxt->vstate->node)
4994 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004995 goto cont;
4996 }
4997 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004998 xmlNodePtr cur;
4999
5000 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005001 DEBUG_VALID_MSG("Failure, rollback");
5002 if (vstateVPop(ctxt) < 0 ) {
5003 DEBUG_VALID_MSG("exhaustion, failed");
5004 return(0);
5005 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005006 if (cur != ctxt->vstate->node)
5007 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005008 goto cont;
5009 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005010 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005011}
Daniel Veillard23e73572002-09-19 19:56:43 +00005012#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005013
5014/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00005015 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005016 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00005017 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005018 * @content: An element
5019 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5020 *
5021 * This will dump the list of elements to the buffer
5022 * Intended just for the debug routine
5023 */
5024static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00005025xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005026 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00005027 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005028
5029 if (node == NULL) return;
5030 if (glob) strcat(buf, "(");
5031 cur = node;
5032 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005033 len = strlen(buf);
5034 if (size - len < 50) {
5035 if ((size - len > 4) && (buf[len - 1] != '.'))
5036 strcat(buf, " ...");
5037 return;
5038 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005039 switch (cur->type) {
5040 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005041 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005042 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005043 if ((size - len > 4) && (buf[len - 1] != '.'))
5044 strcat(buf, " ...");
5045 return;
5046 }
5047 strcat(buf, (char *) cur->ns->prefix);
5048 strcat(buf, ":");
5049 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005050 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005051 if ((size - len > 4) && (buf[len - 1] != '.'))
5052 strcat(buf, " ...");
5053 return;
5054 }
5055 strcat(buf, (char *) cur->name);
5056 if (cur->next != NULL)
5057 strcat(buf, " ");
5058 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005059 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005060 if (xmlIsBlankNode(cur))
5061 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005062 case XML_CDATA_SECTION_NODE:
5063 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005064 strcat(buf, "CDATA");
5065 if (cur->next != NULL)
5066 strcat(buf, " ");
5067 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005068 case XML_ATTRIBUTE_NODE:
5069 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005070#ifdef LIBXML_DOCB_ENABLED
5071 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005072#endif
5073 case XML_HTML_DOCUMENT_NODE:
5074 case XML_DOCUMENT_TYPE_NODE:
5075 case XML_DOCUMENT_FRAG_NODE:
5076 case XML_NOTATION_NODE:
5077 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005078 strcat(buf, "???");
5079 if (cur->next != NULL)
5080 strcat(buf, " ");
5081 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005082 case XML_ENTITY_NODE:
5083 case XML_PI_NODE:
5084 case XML_DTD_NODE:
5085 case XML_COMMENT_NODE:
5086 case XML_ELEMENT_DECL:
5087 case XML_ATTRIBUTE_DECL:
5088 case XML_ENTITY_DECL:
5089 case XML_XINCLUDE_START:
5090 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005091 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005092 }
5093 cur = cur->next;
5094 }
5095 if (glob) strcat(buf, ")");
5096}
5097
5098/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005099 * xmlValidateElementContent:
5100 * @ctxt: the validation context
5101 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005102 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005103 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005104 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005105 *
5106 * Try to validate the content model of an element
5107 *
5108 * returns 1 if valid or 0 if not and -1 in case of error
5109 */
5110
5111static int
5112xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005113 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00005114 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00005115#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00005116 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00005117#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00005118 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005119 xmlElementContentPtr cont;
5120 const xmlChar *name;
5121
5122 if (elemDecl == NULL)
5123 return(-1);
5124 cont = elemDecl->content;
5125 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005126
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005127#ifdef LIBXML_REGEXP_ENABLED
5128 /* Build the regexp associated to the content model */
5129 if (elemDecl->contModel == NULL)
5130 ret = xmlValidBuildContentModel(ctxt, elemDecl);
5131 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005132 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005133 } else {
5134 xmlRegExecCtxtPtr exec;
5135
Daniel Veillardec498e12003-02-05 11:01:50 +00005136 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5137 return(-1);
5138 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005139 ctxt->nodeMax = 0;
5140 ctxt->nodeNr = 0;
5141 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005142 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5143 if (exec != NULL) {
5144 cur = child;
5145 while (cur != NULL) {
5146 switch (cur->type) {
5147 case XML_ENTITY_REF_NODE:
5148 /*
5149 * Push the current node to be able to roll back
5150 * and process within the entity
5151 */
5152 if ((cur->children != NULL) &&
5153 (cur->children->children != NULL)) {
5154 nodeVPush(ctxt, cur);
5155 cur = cur->children->children;
5156 continue;
5157 }
5158 break;
5159 case XML_TEXT_NODE:
5160 if (xmlIsBlankNode(cur))
5161 break;
5162 ret = 0;
5163 goto fail;
5164 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00005165 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005166 ret = 0;
5167 goto fail;
5168 case XML_ELEMENT_NODE:
5169 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005170 xmlChar fn[50];
5171 xmlChar *fullname;
5172
5173 fullname = xmlBuildQName(cur->name,
5174 cur->ns->prefix, fn, 50);
5175 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005176 ret = -1;
5177 goto fail;
5178 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005179 ret = xmlRegExecPushString(exec, fullname, NULL);
5180 if ((fullname != fn) && (fullname != cur->name))
5181 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005182 } else {
5183 ret = xmlRegExecPushString(exec, cur->name, NULL);
5184 }
5185 break;
5186 default:
5187 break;
5188 }
5189 /*
5190 * Switch to next element
5191 */
5192 cur = cur->next;
5193 while (cur == NULL) {
5194 cur = nodeVPop(ctxt);
5195 if (cur == NULL)
5196 break;
5197 cur = cur->next;
5198 }
5199 }
5200 ret = xmlRegExecPushString(exec, NULL, NULL);
5201fail:
5202 xmlRegFreeExecCtxt(exec);
5203 }
5204 }
5205#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005206 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005207 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005208 */
5209 ctxt->vstateMax = 8;
5210 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5211 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5212 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005213 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005214 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005215 }
5216 /*
5217 * The first entry in the stack is reserved to the current state
5218 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005219 ctxt->nodeMax = 0;
5220 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005221 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005222 ctxt->vstate = &ctxt->vstateTab[0];
5223 ctxt->vstateNr = 1;
5224 CONT = cont;
5225 NODE = child;
5226 DEPTH = 0;
5227 OCCURS = 0;
5228 STATE = 0;
5229 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005230 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005231 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5232 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005233 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005234 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005235 /*
5236 * An entities reference appeared at this level.
5237 * Buid a minimal representation of this node content
5238 * sufficient to run the validation process on it
5239 */
5240 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005241 cur = child;
5242 while (cur != NULL) {
5243 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005244 case XML_ENTITY_REF_NODE:
5245 /*
5246 * Push the current node to be able to roll back
5247 * and process within the entity
5248 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005249 if ((cur->children != NULL) &&
5250 (cur->children->children != NULL)) {
5251 nodeVPush(ctxt, cur);
5252 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005253 continue;
5254 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005255 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005256 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005257 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005258 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005259 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005260 case XML_CDATA_SECTION_NODE:
5261 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005262 case XML_ELEMENT_NODE:
5263 /*
5264 * Allocate a new node and minimally fills in
5265 * what's required
5266 */
5267 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5268 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005269 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005270 xmlFreeNodeList(repl);
5271 ret = -1;
5272 goto done;
5273 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005274 tmp->type = cur->type;
5275 tmp->name = cur->name;
5276 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005277 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005278 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005279 if (repl == NULL)
5280 repl = last = tmp;
5281 else {
5282 last->next = tmp;
5283 last = tmp;
5284 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005285 if (cur->type == XML_CDATA_SECTION_NODE) {
5286 /*
5287 * E59 spaces in CDATA does not match the
5288 * nonterminal S
5289 */
5290 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5291 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005292 break;
5293 default:
5294 break;
5295 }
5296 /*
5297 * Switch to next element
5298 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005299 cur = cur->next;
5300 while (cur == NULL) {
5301 cur = nodeVPop(ctxt);
5302 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005303 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005304 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005305 }
5306 }
5307
5308 /*
5309 * Relaunch the validation
5310 */
5311 ctxt->vstate = &ctxt->vstateTab[0];
5312 ctxt->vstateNr = 1;
5313 CONT = cont;
5314 NODE = repl;
5315 DEPTH = 0;
5316 OCCURS = 0;
5317 STATE = 0;
5318 ret = xmlValidateElementType(ctxt);
5319 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005320#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005321 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005322 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5323 char expr[5000];
5324 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005325
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005326 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005327 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005328 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005329#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005330 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005331 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005332 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005333#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005334 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005335
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005336 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005337 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5338 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5339 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005340 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005341 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5342 "Element content does not follow the DTD, expecting %s, got %s\n",
5343 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005344 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005345 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005346 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005347 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005348 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005349 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005350 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005351 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5352 "Element content does not follow the DTD\n",
5353 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005354 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005355 }
5356 ret = 0;
5357 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005358 if (ret == -3)
5359 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005360
Daniel Veillard23e73572002-09-19 19:56:43 +00005361#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005362done:
5363 /*
5364 * Deallocate the copy if done, and free up the validation stack
5365 */
5366 while (repl != NULL) {
5367 tmp = repl->next;
5368 xmlFree(repl);
5369 repl = tmp;
5370 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005371 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005372 if (ctxt->vstateTab != NULL) {
5373 xmlFree(ctxt->vstateTab);
5374 ctxt->vstateTab = NULL;
5375 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005376#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005377 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005378 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005379 if (ctxt->nodeTab != NULL) {
5380 xmlFree(ctxt->nodeTab);
5381 ctxt->nodeTab = NULL;
5382 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005383 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005384
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005385}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005386
Owen Taylor3473f882001-02-23 17:55:21 +00005387/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005388 * xmlValidateCdataElement:
5389 * @ctxt: the validation context
5390 * @doc: a document instance
5391 * @elem: an element instance
5392 *
5393 * Check that an element follows #CDATA
5394 *
5395 * returns 1 if valid or 0 otherwise
5396 */
5397static int
5398xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5399 xmlNodePtr elem) {
5400 int ret = 1;
5401 xmlNodePtr cur, child;
5402
Daniel Veillardceb09b92002-10-04 11:46:37 +00005403 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005404 return(0);
5405
5406 child = elem->children;
5407
5408 cur = child;
5409 while (cur != NULL) {
5410 switch (cur->type) {
5411 case XML_ENTITY_REF_NODE:
5412 /*
5413 * Push the current node to be able to roll back
5414 * and process within the entity
5415 */
5416 if ((cur->children != NULL) &&
5417 (cur->children->children != NULL)) {
5418 nodeVPush(ctxt, cur);
5419 cur = cur->children->children;
5420 continue;
5421 }
5422 break;
5423 case XML_COMMENT_NODE:
5424 case XML_PI_NODE:
5425 case XML_TEXT_NODE:
5426 case XML_CDATA_SECTION_NODE:
5427 break;
5428 default:
5429 ret = 0;
5430 goto done;
5431 }
5432 /*
5433 * Switch to next element
5434 */
5435 cur = cur->next;
5436 while (cur == NULL) {
5437 cur = nodeVPop(ctxt);
5438 if (cur == NULL)
5439 break;
5440 cur = cur->next;
5441 }
5442 }
5443done:
5444 ctxt->nodeMax = 0;
5445 ctxt->nodeNr = 0;
5446 if (ctxt->nodeTab != NULL) {
5447 xmlFree(ctxt->nodeTab);
5448 ctxt->nodeTab = NULL;
5449 }
5450 return(ret);
5451}
5452
5453/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005454 * xmlValidateCheckMixed:
5455 * @ctxt: the validation context
5456 * @cont: the mixed content model
5457 * @qname: the qualified name as appearing in the serialization
5458 *
5459 * Check if the given node is part of the content model.
5460 *
5461 * Returns 1 if yes, 0 if no, -1 in case of error
5462 */
5463static int
William M. Brackedb65a72004-02-06 07:36:04 +00005464xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005465 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005466 const xmlChar *name;
5467 int plen;
5468 name = xmlSplitQName3(qname, &plen);
5469
5470 if (name == NULL) {
5471 while (cont != NULL) {
5472 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5473 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5474 return(1);
5475 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5476 (cont->c1 != NULL) &&
5477 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5478 if ((cont->c1->prefix == NULL) &&
5479 (xmlStrEqual(cont->c1->name, qname)))
5480 return(1);
5481 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5482 (cont->c1 == NULL) ||
5483 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005484 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5485 "Internal: MIXED struct corrupted\n",
5486 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005487 break;
5488 }
5489 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005490 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005491 } else {
5492 while (cont != NULL) {
5493 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5494 if ((cont->prefix != NULL) &&
5495 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5496 (xmlStrEqual(cont->name, name)))
5497 return(1);
5498 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5499 (cont->c1 != NULL) &&
5500 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5501 if ((cont->c1->prefix != NULL) &&
5502 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5503 (xmlStrEqual(cont->c1->name, name)))
5504 return(1);
5505 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5506 (cont->c1 == NULL) ||
5507 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005508 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5509 "Internal: MIXED struct corrupted\n",
5510 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005511 break;
5512 }
5513 cont = cont->c2;
5514 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005515 }
5516 return(0);
5517}
5518
5519/**
5520 * xmlValidGetElemDecl:
5521 * @ctxt: the validation context
5522 * @doc: a document instance
5523 * @elem: an element instance
5524 * @extsubset: pointer, (out) indicate if the declaration was found
5525 * in the external subset.
5526 *
5527 * Finds a declaration associated to an element in the document.
5528 *
5529 * returns the pointer to the declaration or NULL if not found.
5530 */
5531static xmlElementPtr
5532xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5533 xmlNodePtr elem, int *extsubset) {
5534 xmlElementPtr elemDecl = NULL;
5535 const xmlChar *prefix = NULL;
5536
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005537 if ((ctxt == NULL) || (doc == NULL) ||
5538 (elem == NULL) || (elem->name == NULL))
5539 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005540 if (extsubset != NULL)
5541 *extsubset = 0;
5542
5543 /*
5544 * Fetch the declaration for the qualified name
5545 */
5546 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5547 prefix = elem->ns->prefix;
5548
5549 if (prefix != NULL) {
5550 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5551 elem->name, prefix);
5552 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5553 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5554 elem->name, prefix);
5555 if ((elemDecl != NULL) && (extsubset != NULL))
5556 *extsubset = 1;
5557 }
5558 }
5559
5560 /*
5561 * Fetch the declaration for the non qualified name
5562 * This is "non-strict" validation should be done on the
5563 * full QName but in that case being flexible makes sense.
5564 */
5565 if (elemDecl == NULL) {
5566 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5567 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5568 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5569 if ((elemDecl != NULL) && (extsubset != NULL))
5570 *extsubset = 1;
5571 }
5572 }
5573 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005574 xmlErrValidNode(ctxt, elem,
5575 XML_DTD_UNKNOWN_ELEM,
5576 "No declaration for element %s\n",
5577 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005578 }
5579 return(elemDecl);
5580}
5581
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005582#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005583/**
5584 * xmlValidatePushElement:
5585 * @ctxt: the validation context
5586 * @doc: a document instance
5587 * @elem: an element instance
5588 * @qname: the qualified name as appearing in the serialization
5589 *
5590 * Push a new element start on the validation stack.
5591 *
5592 * returns 1 if no validation problem was found or 0 otherwise
5593 */
5594int
5595xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5596 xmlNodePtr elem, const xmlChar *qname) {
5597 int ret = 1;
5598 xmlElementPtr eDecl;
5599 int extsubset = 0;
5600
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005601 if (ctxt == NULL)
5602 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005603/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005604 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5605 xmlValidStatePtr state = ctxt->vstate;
5606 xmlElementPtr elemDecl;
5607
5608 /*
5609 * Check the new element agaisnt the content model of the new elem.
5610 */
5611 if (state->elemDecl != NULL) {
5612 elemDecl = state->elemDecl;
5613
5614 switch(elemDecl->etype) {
5615 case XML_ELEMENT_TYPE_UNDEFINED:
5616 ret = 0;
5617 break;
5618 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005619 xmlErrValidNode(ctxt, state->node,
5620 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005621 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005622 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005623 ret = 0;
5624 break;
5625 case XML_ELEMENT_TYPE_ANY:
5626 /* I don't think anything is required then */
5627 break;
5628 case XML_ELEMENT_TYPE_MIXED:
5629 /* simple case of declared as #PCDATA */
5630 if ((elemDecl->content != NULL) &&
5631 (elemDecl->content->type ==
5632 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005633 xmlErrValidNode(ctxt, state->node,
5634 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005635 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005636 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005637 ret = 0;
5638 } else {
5639 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5640 qname);
5641 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005642 xmlErrValidNode(ctxt, state->node,
5643 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005644 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005645 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005646 }
5647 }
5648 break;
5649 case XML_ELEMENT_TYPE_ELEMENT:
5650 /*
5651 * TODO:
5652 * VC: Standalone Document Declaration
5653 * - element types with element content, if white space
5654 * occurs directly within any instance of those types.
5655 */
5656 if (state->exec != NULL) {
5657 ret = xmlRegExecPushString(state->exec, qname, NULL);
5658 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005659 xmlErrValidNode(ctxt, state->node,
5660 XML_DTD_CONTENT_MODEL,
5661 "Element %s content does not follow the DTD, Misplaced %s\n",
5662 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005663 ret = 0;
5664 } else {
5665 ret = 1;
5666 }
5667 }
5668 break;
5669 }
5670 }
5671 }
5672 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5673 vstateVPush(ctxt, eDecl, elem);
5674 return(ret);
5675}
5676
5677/**
5678 * xmlValidatePushCData:
5679 * @ctxt: the validation context
5680 * @data: some character data read
5681 * @len: the lenght of the data
5682 *
5683 * check the CData parsed for validation in the current stack
5684 *
5685 * returns 1 if no validation problem was found or 0 otherwise
5686 */
5687int
5688xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5689 int ret = 1;
5690
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005691/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005692 if (ctxt == NULL)
5693 return(0);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005694 if (len <= 0)
5695 return(ret);
5696 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5697 xmlValidStatePtr state = ctxt->vstate;
5698 xmlElementPtr elemDecl;
5699
5700 /*
5701 * Check the new element agaisnt the content model of the new elem.
5702 */
5703 if (state->elemDecl != NULL) {
5704 elemDecl = state->elemDecl;
5705
5706 switch(elemDecl->etype) {
5707 case XML_ELEMENT_TYPE_UNDEFINED:
5708 ret = 0;
5709 break;
5710 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005711 xmlErrValidNode(ctxt, state->node,
5712 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005713 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005714 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005715 ret = 0;
5716 break;
5717 case XML_ELEMENT_TYPE_ANY:
5718 break;
5719 case XML_ELEMENT_TYPE_MIXED:
5720 break;
5721 case XML_ELEMENT_TYPE_ELEMENT:
5722 if (len > 0) {
5723 int i;
5724
5725 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005726 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005727 xmlErrValidNode(ctxt, state->node,
5728 XML_DTD_CONTENT_MODEL,
5729 "Element %s content does not follow the DTD, Text not allowed\n",
5730 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005731 ret = 0;
5732 goto done;
5733 }
5734 }
5735 /*
5736 * TODO:
5737 * VC: Standalone Document Declaration
5738 * element types with element content, if white space
5739 * occurs directly within any instance of those types.
5740 */
5741 }
5742 break;
5743 }
5744 }
5745 }
5746done:
5747 return(ret);
5748}
5749
5750/**
5751 * xmlValidatePopElement:
5752 * @ctxt: the validation context
5753 * @doc: a document instance
5754 * @elem: an element instance
5755 * @qname: the qualified name as appearing in the serialization
5756 *
5757 * Pop the element end from the validation stack.
5758 *
5759 * returns 1 if no validation problem was found or 0 otherwise
5760 */
5761int
5762xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005763 xmlNodePtr elem ATTRIBUTE_UNUSED,
5764 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005765 int ret = 1;
5766
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005767 if (ctxt == NULL)
5768 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005769/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005770 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5771 xmlValidStatePtr state = ctxt->vstate;
5772 xmlElementPtr elemDecl;
5773
5774 /*
5775 * Check the new element agaisnt the content model of the new elem.
5776 */
5777 if (state->elemDecl != NULL) {
5778 elemDecl = state->elemDecl;
5779
5780 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5781 if (state->exec != NULL) {
5782 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5783 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005784 xmlErrValidNode(ctxt, state->node,
5785 XML_DTD_CONTENT_MODEL,
5786 "Element %s content does not follow the DTD, Expecting more child\n",
5787 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005788 } else {
5789 /*
5790 * previous validation errors should not generate
5791 * a new one here
5792 */
5793 ret = 1;
5794 }
5795 }
5796 }
5797 }
5798 vstateVPop(ctxt);
5799 }
5800 return(ret);
5801}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005802#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005803
5804/**
Owen Taylor3473f882001-02-23 17:55:21 +00005805 * xmlValidateOneElement:
5806 * @ctxt: the validation context
5807 * @doc: a document instance
5808 * @elem: an element instance
5809 *
5810 * Try to validate a single element and it's attributes,
5811 * basically it does the following checks as described by the
5812 * XML-1.0 recommendation:
5813 * - [ VC: Element Valid ]
5814 * - [ VC: Required Attribute ]
5815 * Then call xmlValidateOneAttribute() for each attribute present.
5816 *
5817 * The ID/IDREF checkings are done separately
5818 *
5819 * returns 1 if valid or 0 otherwise
5820 */
5821
5822int
5823xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5824 xmlNodePtr elem) {
5825 xmlElementPtr elemDecl = NULL;
5826 xmlElementContentPtr cont;
5827 xmlAttributePtr attr;
5828 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005829 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005830 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005831 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005832
5833 CHECK_DTD;
5834
5835 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005836 switch (elem->type) {
5837 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005838 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5839 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005840 return(0);
5841 case XML_TEXT_NODE:
5842 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005843 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5844 "Text element has children !\n",
5845 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005846 return(0);
5847 }
5848 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005849 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5850 "Text element has attribute !\n",
5851 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005852 return(0);
5853 }
5854 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005855 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5856 "Text element has namespace !\n",
5857 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005858 return(0);
5859 }
5860 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005861 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5862 "Text element has namespace !\n",
5863 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005864 return(0);
5865 }
5866 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005867 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5868 "Text element has no content !\n",
5869 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005870 return(0);
5871 }
5872 return(1);
5873 case XML_XINCLUDE_START:
5874 case XML_XINCLUDE_END:
5875 return(1);
5876 case XML_CDATA_SECTION_NODE:
5877 case XML_ENTITY_REF_NODE:
5878 case XML_PI_NODE:
5879 case XML_COMMENT_NODE:
5880 return(1);
5881 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005882 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5883 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005884 return(0);
5885 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005886 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5887 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005888 return(0);
5889 case XML_DOCUMENT_NODE:
5890 case XML_DOCUMENT_TYPE_NODE:
5891 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005892 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5893 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005894 return(0);
5895 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005896 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5897 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005898 return(0);
5899 case XML_ELEMENT_NODE:
5900 break;
5901 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005902 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5903 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005904 return(0);
5905 }
Owen Taylor3473f882001-02-23 17:55:21 +00005906
5907 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005908 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005909 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005910 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5911 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005912 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005913
Daniel Veillardea7751d2002-12-20 00:16:24 +00005914 /*
5915 * If vstateNr is not zero that means continuous validation is
5916 * activated, do not try to check the content model at that level.
5917 */
5918 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005919 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005920 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005921 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005922 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5923 "No declaration for element %s\n",
5924 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005925 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005926 case XML_ELEMENT_TYPE_EMPTY:
5927 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005928 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005929 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005930 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005931 ret = 0;
5932 }
5933 break;
5934 case XML_ELEMENT_TYPE_ANY:
5935 /* I don't think anything is required then */
5936 break;
5937 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005938
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005939 /* simple case of declared as #PCDATA */
5940 if ((elemDecl->content != NULL) &&
5941 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5942 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5943 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005944 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005945 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005946 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005947 }
5948 break;
5949 }
Owen Taylor3473f882001-02-23 17:55:21 +00005950 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005951 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005952 while (child != NULL) {
5953 if (child->type == XML_ELEMENT_NODE) {
5954 name = child->name;
5955 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005956 xmlChar fn[50];
5957 xmlChar *fullname;
5958
5959 fullname = xmlBuildQName(child->name, child->ns->prefix,
5960 fn, 50);
5961 if (fullname == NULL)
5962 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005963 cont = elemDecl->content;
5964 while (cont != NULL) {
5965 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005966 if (xmlStrEqual(cont->name, fullname))
5967 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005968 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5969 (cont->c1 != NULL) &&
5970 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005971 if (xmlStrEqual(cont->c1->name, fullname))
5972 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005973 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5974 (cont->c1 == NULL) ||
5975 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005976 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5977 "Internal: MIXED struct corrupted\n",
5978 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005979 break;
5980 }
5981 cont = cont->c2;
5982 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005983 if ((fullname != fn) && (fullname != child->name))
5984 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005985 if (cont != NULL)
5986 goto child_ok;
5987 }
5988 cont = elemDecl->content;
5989 while (cont != NULL) {
5990 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5991 if (xmlStrEqual(cont->name, name)) break;
5992 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5993 (cont->c1 != NULL) &&
5994 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5995 if (xmlStrEqual(cont->c1->name, name)) break;
5996 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5997 (cont->c1 == NULL) ||
5998 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005999 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
6000 "Internal: MIXED struct corrupted\n",
6001 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006002 break;
6003 }
6004 cont = cont->c2;
6005 }
6006 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006007 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006008 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006009 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006010 ret = 0;
6011 }
6012 }
6013child_ok:
6014 child = child->next;
6015 }
6016 break;
6017 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006018 if ((doc->standalone == 1) && (extsubset == 1)) {
6019 /*
6020 * VC: Standalone Document Declaration
6021 * - element types with element content, if white space
6022 * occurs directly within any instance of those types.
6023 */
6024 child = elem->children;
6025 while (child != NULL) {
6026 if (child->type == XML_TEXT_NODE) {
6027 const xmlChar *content = child->content;
6028
William M. Brack76e95df2003-10-18 16:20:14 +00006029 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006030 content++;
6031 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006032 xmlErrValidNode(ctxt, elem,
6033 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006034"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006035 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006036 ret = 0;
6037 break;
6038 }
6039 }
6040 child =child->next;
6041 }
6042 }
Owen Taylor3473f882001-02-23 17:55:21 +00006043 child = elem->children;
6044 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00006045 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006046 if (tmp <= 0)
6047 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006048 break;
6049 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00006050 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00006051
6052 /* [ VC: Required Attribute ] */
6053 attr = elemDecl->attributes;
6054 while (attr != NULL) {
6055 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006056 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006057
Daniel Veillarde4301c82002-02-13 13:32:35 +00006058 if ((attr->prefix == NULL) &&
6059 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6060 xmlNsPtr ns;
6061
6062 ns = elem->nsDef;
6063 while (ns != NULL) {
6064 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006065 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006066 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006067 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006068 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6069 xmlNsPtr ns;
6070
6071 ns = elem->nsDef;
6072 while (ns != NULL) {
6073 if (xmlStrEqual(attr->name, ns->prefix))
6074 goto found;
6075 ns = ns->next;
6076 }
6077 } else {
6078 xmlAttrPtr attrib;
6079
6080 attrib = elem->properties;
6081 while (attrib != NULL) {
6082 if (xmlStrEqual(attrib->name, attr->name)) {
6083 if (attr->prefix != NULL) {
6084 xmlNsPtr nameSpace = attrib->ns;
6085
6086 if (nameSpace == NULL)
6087 nameSpace = elem->ns;
6088 /*
6089 * qualified names handling is problematic, having a
6090 * different prefix should be possible but DTDs don't
6091 * allow to define the URI instead of the prefix :-(
6092 */
6093 if (nameSpace == NULL) {
6094 if (qualified < 0)
6095 qualified = 0;
6096 } else if (!xmlStrEqual(nameSpace->prefix,
6097 attr->prefix)) {
6098 if (qualified < 1)
6099 qualified = 1;
6100 } else
6101 goto found;
6102 } else {
6103 /*
6104 * We should allow applications to define namespaces
6105 * for their application even if the DTD doesn't
6106 * carry one, otherwise, basically we would always
6107 * break.
6108 */
6109 goto found;
6110 }
6111 }
6112 attrib = attrib->next;
6113 }
Owen Taylor3473f882001-02-23 17:55:21 +00006114 }
6115 if (qualified == -1) {
6116 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006117 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006118 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006119 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006120 ret = 0;
6121 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006122 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006123 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00006124 elem->name, attr->prefix,attr->name);
6125 ret = 0;
6126 }
6127 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006128 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006129 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006130 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006131 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006132 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006133 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006134 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006135 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006136 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
6137 /*
6138 * Special tests checking #FIXED namespace declarations
6139 * have the right value since this is not done as an
6140 * attribute checking
6141 */
6142 if ((attr->prefix == NULL) &&
6143 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6144 xmlNsPtr ns;
6145
6146 ns = elem->nsDef;
6147 while (ns != NULL) {
6148 if (ns->prefix == NULL) {
6149 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006150 xmlErrValidNode(ctxt, elem,
6151 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00006152 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006153 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006154 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006155 }
6156 goto found;
6157 }
6158 ns = ns->next;
6159 }
6160 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6161 xmlNsPtr ns;
6162
6163 ns = elem->nsDef;
6164 while (ns != NULL) {
6165 if (xmlStrEqual(attr->name, ns->prefix)) {
6166 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006167 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006168 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006169 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006170 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006171 }
6172 goto found;
6173 }
6174 ns = ns->next;
6175 }
6176 }
Owen Taylor3473f882001-02-23 17:55:21 +00006177 }
6178found:
6179 attr = attr->nexth;
6180 }
6181 return(ret);
6182}
6183
6184/**
6185 * xmlValidateRoot:
6186 * @ctxt: the validation context
6187 * @doc: a document instance
6188 *
6189 * Try to validate a the root element
6190 * basically it does the following check as described by the
6191 * XML-1.0 recommendation:
6192 * - [ VC: Root Element Type ]
6193 * it doesn't try to recurse or apply other check to the element
6194 *
6195 * returns 1 if valid or 0 otherwise
6196 */
6197
6198int
6199xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6200 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006201 int ret;
6202
Owen Taylor3473f882001-02-23 17:55:21 +00006203 if (doc == NULL) return(0);
6204
6205 root = xmlDocGetRootElement(doc);
6206 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006207 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6208 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006209 return(0);
6210 }
6211
6212 /*
6213 * When doing post validation against a separate DTD, those may
6214 * no internal subset has been generated
6215 */
6216 if ((doc->intSubset != NULL) &&
6217 (doc->intSubset->name != NULL)) {
6218 /*
6219 * Check first the document root against the NQName
6220 */
6221 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6222 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006223 xmlChar fn[50];
6224 xmlChar *fullname;
6225
6226 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6227 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006228 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006229 return(0);
6230 }
6231 ret = xmlStrEqual(doc->intSubset->name, fullname);
6232 if ((fullname != fn) && (fullname != root->name))
6233 xmlFree(fullname);
6234 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006235 goto name_ok;
6236 }
6237 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6238 (xmlStrEqual(root->name, BAD_CAST "html")))
6239 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006240 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6241 "root and DTD name do not match '%s' and '%s'\n",
6242 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006243 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006244 }
6245 }
6246name_ok:
6247 return(1);
6248}
6249
6250
6251/**
6252 * xmlValidateElement:
6253 * @ctxt: the validation context
6254 * @doc: a document instance
6255 * @elem: an element instance
6256 *
6257 * Try to validate the subtree under an element
6258 *
6259 * returns 1 if valid or 0 otherwise
6260 */
6261
6262int
6263xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6264 xmlNodePtr child;
6265 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006266 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006267 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006268 int ret = 1;
6269
6270 if (elem == NULL) return(0);
6271
6272 /*
6273 * XInclude elements were added after parsing in the infoset,
6274 * they don't really mean anything validation wise.
6275 */
6276 if ((elem->type == XML_XINCLUDE_START) ||
6277 (elem->type == XML_XINCLUDE_END))
6278 return(1);
6279
6280 CHECK_DTD;
6281
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006282 /*
6283 * Entities references have to be handled separately
6284 */
6285 if (elem->type == XML_ENTITY_REF_NODE) {
6286 return(1);
6287 }
6288
Owen Taylor3473f882001-02-23 17:55:21 +00006289 ret &= xmlValidateOneElement(ctxt, doc, elem);
6290 attr = elem->properties;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006291 while (attr != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006292 value = xmlNodeListGetString(doc, attr->children, 0);
6293 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6294 if (value != NULL)
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006295 xmlFree((char *)value);
Owen Taylor3473f882001-02-23 17:55:21 +00006296 attr= attr->next;
6297 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006298 ns = elem->nsDef;
6299 while (ns != NULL) {
Daniel Veillard1f5c9892003-12-29 17:09:55 +00006300 if (elem->ns == NULL)
6301 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6302 ns, ns->href);
6303 else
6304 ret &= xmlValidateOneNamespace(ctxt, doc, elem, elem->ns->prefix,
6305 ns, ns->href);
Daniel Veillarde133dd82003-10-30 10:42:20 +00006306 ns = ns->next;
6307 }
Owen Taylor3473f882001-02-23 17:55:21 +00006308 child = elem->children;
6309 while (child != NULL) {
6310 ret &= xmlValidateElement(ctxt, doc, child);
6311 child = child->next;
6312 }
6313
6314 return(ret);
6315}
6316
Daniel Veillard8730c562001-02-26 10:49:57 +00006317/**
6318 * xmlValidateRef:
6319 * @ref: A reference to be validated
6320 * @ctxt: Validation context
6321 * @name: Name of ID we are searching for
6322 *
6323 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006324static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006325xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006326 const xmlChar *name) {
6327 xmlAttrPtr id;
6328 xmlAttrPtr attr;
6329
6330 if (ref == NULL)
6331 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006332 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006333 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006334 attr = ref->attr;
6335 if (attr == NULL) {
6336 xmlChar *dup, *str = NULL, *cur, save;
6337
6338 dup = xmlStrdup(name);
6339 if (dup == NULL) {
6340 ctxt->valid = 0;
6341 return;
6342 }
6343 cur = dup;
6344 while (*cur != 0) {
6345 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006346 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006347 save = *cur;
6348 *cur = 0;
6349 id = xmlGetID(ctxt->doc, str);
6350 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006351 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006352 "attribute %s line %d references an unknown ID \"%s\"\n",
6353 ref->name, ref->lineno, str);
6354 ctxt->valid = 0;
6355 }
6356 if (save == 0)
6357 break;
6358 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006359 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006360 }
6361 xmlFree(dup);
6362 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006363 id = xmlGetID(ctxt->doc, name);
6364 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006365 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006366 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006367 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006368 ctxt->valid = 0;
6369 }
6370 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6371 xmlChar *dup, *str = NULL, *cur, save;
6372
6373 dup = xmlStrdup(name);
6374 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006375 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006376 ctxt->valid = 0;
6377 return;
6378 }
6379 cur = dup;
6380 while (*cur != 0) {
6381 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006382 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006383 save = *cur;
6384 *cur = 0;
6385 id = xmlGetID(ctxt->doc, str);
6386 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006387 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006388 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006389 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006390 ctxt->valid = 0;
6391 }
6392 if (save == 0)
6393 break;
6394 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006395 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006396 }
6397 xmlFree(dup);
6398 }
6399}
6400
6401/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006402 * xmlWalkValidateList:
6403 * @data: Contents of current link
6404 * @user: Value supplied by the user
6405 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006406 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006407 */
6408static int
6409xmlWalkValidateList(const void *data, const void *user)
6410{
6411 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6412 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6413 return 1;
6414}
6415
6416/**
6417 * xmlValidateCheckRefCallback:
6418 * @ref_list: List of references
6419 * @ctxt: Validation context
6420 * @name: Name of ID we are searching for
6421 *
6422 */
6423static void
6424xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6425 const xmlChar *name) {
6426 xmlValidateMemo memo;
6427
6428 if (ref_list == NULL)
6429 return;
6430 memo.ctxt = ctxt;
6431 memo.name = name;
6432
6433 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6434
6435}
6436
6437/**
Owen Taylor3473f882001-02-23 17:55:21 +00006438 * xmlValidateDocumentFinal:
6439 * @ctxt: the validation context
6440 * @doc: a document instance
6441 *
6442 * Does the final step for the document validation once all the
6443 * incremental validation steps have been completed
6444 *
6445 * basically it does the following checks described by the XML Rec
6446 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006447 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006448 *
6449 * returns 1 if valid or 0 otherwise
6450 */
6451
6452int
6453xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6454 xmlRefTablePtr table;
6455
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006456 if (ctxt == NULL)
6457 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006458 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006459 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6460 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006461 return(0);
6462 }
6463
6464 /*
6465 * Check all the NOTATION/NOTATIONS attributes
6466 */
6467 /*
6468 * Check all the ENTITY/ENTITIES attributes definition for validity
6469 */
6470 /*
6471 * Check all the IDREF/IDREFS attributes definition for validity
6472 */
6473 table = (xmlRefTablePtr) doc->refs;
6474 ctxt->doc = doc;
6475 ctxt->valid = 1;
6476 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6477 return(ctxt->valid);
6478}
6479
6480/**
6481 * xmlValidateDtd:
6482 * @ctxt: the validation context
6483 * @doc: a document instance
6484 * @dtd: a dtd instance
6485 *
6486 * Try to validate the document against the dtd instance
6487 *
William M. Brack367df6e2004-10-23 18:14:36 +00006488 * Basically it does check all the definitions in the DtD.
6489 * Note the the internal subset (if present) is de-coupled
6490 * (i.e. not used), which could give problems if ID or IDREF
6491 * is present.
Owen Taylor3473f882001-02-23 17:55:21 +00006492 *
6493 * returns 1 if valid or 0 otherwise
6494 */
6495
6496int
6497xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6498 int ret;
William M. Brack367df6e2004-10-23 18:14:36 +00006499 xmlDtdPtr oldExt, oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006500 xmlNodePtr root;
6501
6502 if (dtd == NULL) return(0);
6503 if (doc == NULL) return(0);
6504 oldExt = doc->extSubset;
William M. Brack367df6e2004-10-23 18:14:36 +00006505 oldInt = doc->intSubset;
Owen Taylor3473f882001-02-23 17:55:21 +00006506 doc->extSubset = dtd;
William M. Brack367df6e2004-10-23 18:14:36 +00006507 doc->intSubset = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006508 ret = xmlValidateRoot(ctxt, doc);
6509 if (ret == 0) {
6510 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006511 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006512 return(ret);
6513 }
6514 if (doc->ids != NULL) {
6515 xmlFreeIDTable(doc->ids);
6516 doc->ids = NULL;
6517 }
6518 if (doc->refs != NULL) {
6519 xmlFreeRefTable(doc->refs);
6520 doc->refs = NULL;
6521 }
6522 root = xmlDocGetRootElement(doc);
6523 ret = xmlValidateElement(ctxt, doc, root);
6524 ret &= xmlValidateDocumentFinal(ctxt, doc);
6525 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006526 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006527 return(ret);
6528}
6529
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006530static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006531xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6532 const xmlChar *name ATTRIBUTE_UNUSED) {
6533 if (cur == NULL)
6534 return;
6535 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6536 xmlChar *notation = cur->content;
6537
Daniel Veillard878eab02002-02-19 13:46:09 +00006538 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006539 int ret;
6540
6541 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6542 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006543 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006544 }
6545 }
6546 }
6547}
6548
6549static void
Owen Taylor3473f882001-02-23 17:55:21 +00006550xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006551 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006552 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006553 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006554 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006555
Owen Taylor3473f882001-02-23 17:55:21 +00006556 if (cur == NULL)
6557 return;
6558 switch (cur->atype) {
6559 case XML_ATTRIBUTE_CDATA:
6560 case XML_ATTRIBUTE_ID:
6561 case XML_ATTRIBUTE_IDREF :
6562 case XML_ATTRIBUTE_IDREFS:
6563 case XML_ATTRIBUTE_NMTOKEN:
6564 case XML_ATTRIBUTE_NMTOKENS:
6565 case XML_ATTRIBUTE_ENUMERATION:
6566 break;
6567 case XML_ATTRIBUTE_ENTITY:
6568 case XML_ATTRIBUTE_ENTITIES:
6569 case XML_ATTRIBUTE_NOTATION:
6570 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006571
6572 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6573 cur->atype, cur->defaultValue);
6574 if ((ret == 0) && (ctxt->valid == 1))
6575 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006576 }
6577 if (cur->tree != NULL) {
6578 xmlEnumerationPtr tree = cur->tree;
6579 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006580 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006581 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006582 if ((ret == 0) && (ctxt->valid == 1))
6583 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006584 tree = tree->next;
6585 }
6586 }
6587 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006588 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6589 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006590 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006591 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006592 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006593 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006594 return;
6595 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006596
6597 if (doc != NULL)
6598 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6599 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006600 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006601 if ((elem == NULL) && (cur->parent != NULL) &&
6602 (cur->parent->type == XML_DTD_NODE))
6603 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006604 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006605 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006606 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006607 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006608 return;
6609 }
6610 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006611 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006612 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006613 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006614 ctxt->valid = 0;
6615 }
6616 }
Owen Taylor3473f882001-02-23 17:55:21 +00006617}
6618
6619/**
6620 * xmlValidateDtdFinal:
6621 * @ctxt: the validation context
6622 * @doc: a document instance
6623 *
6624 * Does the final step for the dtds validation once all the
6625 * subsets have been parsed
6626 *
6627 * basically it does the following checks described by the XML Rec
6628 * - check that ENTITY and ENTITIES type attributes default or
6629 * possible values matches one of the defined entities.
6630 * - check that NOTATION type attributes default or
6631 * possible values matches one of the defined notations.
6632 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006633 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006634 */
6635
6636int
6637xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006638 xmlDtdPtr dtd;
6639 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006640 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006641
6642 if (doc == NULL) return(0);
6643 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6644 return(0);
6645 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006646 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006647 dtd = doc->intSubset;
6648 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6649 table = (xmlAttributeTablePtr) dtd->attributes;
6650 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006651 }
6652 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006653 entities = (xmlEntitiesTablePtr) dtd->entities;
6654 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6655 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006656 }
6657 dtd = doc->extSubset;
6658 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6659 table = (xmlAttributeTablePtr) dtd->attributes;
6660 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006661 }
6662 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006663 entities = (xmlEntitiesTablePtr) dtd->entities;
6664 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6665 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006666 }
6667 return(ctxt->valid);
6668}
6669
6670/**
6671 * xmlValidateDocument:
6672 * @ctxt: the validation context
6673 * @doc: a document instance
6674 *
6675 * Try to validate the document instance
6676 *
6677 * basically it does the all the checks described by the XML Rec
6678 * i.e. validates the internal and external subset (if present)
6679 * and validate the document tree.
6680 *
6681 * returns 1 if valid or 0 otherwise
6682 */
6683
6684int
6685xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6686 int ret;
6687 xmlNodePtr root;
6688
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006689 if (doc == NULL)
6690 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006691 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006692 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6693 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006694 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006695 }
Owen Taylor3473f882001-02-23 17:55:21 +00006696 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6697 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
William M. Brack8c22f9f2004-08-06 16:23:27 +00006698 xmlChar *sysID;
6699 if (doc->intSubset->SystemID != NULL) {
William M. Brackbebe7302004-08-05 06:46:47 +00006700 sysID = xmlBuildURI(doc->intSubset->SystemID,
6701 doc->URL);
William M. Brack8c22f9f2004-08-06 16:23:27 +00006702 if (sysID == NULL) {
6703 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6704 "Could not build URI for external subset \"%s\"\n",
6705 (const char *) doc->intSubset->SystemID);
6706 return 0;
6707 }
6708 } else
William M. Brackbebe7302004-08-05 06:46:47 +00006709 sysID = NULL;
William M. Brack8c22f9f2004-08-06 16:23:27 +00006710 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
William M. Brackbebe7302004-08-05 06:46:47 +00006711 (const xmlChar *)sysID);
William M. Brackbebe7302004-08-05 06:46:47 +00006712 if (sysID != NULL)
6713 xmlFree(sysID);
Owen Taylor3473f882001-02-23 17:55:21 +00006714 if (doc->extSubset == NULL) {
6715 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006716 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006717 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006718 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006719 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006720 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006721 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006722 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006723 }
6724 return(0);
6725 }
6726 }
6727
6728 if (doc->ids != NULL) {
6729 xmlFreeIDTable(doc->ids);
6730 doc->ids = NULL;
6731 }
6732 if (doc->refs != NULL) {
6733 xmlFreeRefTable(doc->refs);
6734 doc->refs = NULL;
6735 }
6736 ret = xmlValidateDtdFinal(ctxt, doc);
6737 if (!xmlValidateRoot(ctxt, doc)) return(0);
6738
6739 root = xmlDocGetRootElement(doc);
6740 ret &= xmlValidateElement(ctxt, doc, root);
6741 ret &= xmlValidateDocumentFinal(ctxt, doc);
6742 return(ret);
6743}
6744
Owen Taylor3473f882001-02-23 17:55:21 +00006745/************************************************************************
6746 * *
6747 * Routines for dynamic validation editing *
6748 * *
6749 ************************************************************************/
6750
6751/**
6752 * xmlValidGetPotentialChildren:
6753 * @ctree: an element content tree
6754 * @list: an array to store the list of child names
6755 * @len: a pointer to the number of element in the list
6756 * @max: the size of the array
6757 *
6758 * Build/extend a list of potential children allowed by the content tree
6759 *
6760 * returns the number of element in the list, or -1 in case of error.
6761 */
6762
6763int
6764xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6765 int *len, int max) {
6766 int i;
6767
6768 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6769 return(-1);
6770 if (*len >= max) return(*len);
6771
6772 switch (ctree->type) {
6773 case XML_ELEMENT_CONTENT_PCDATA:
6774 for (i = 0; i < *len;i++)
6775 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6776 list[(*len)++] = BAD_CAST "#PCDATA";
6777 break;
6778 case XML_ELEMENT_CONTENT_ELEMENT:
6779 for (i = 0; i < *len;i++)
6780 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6781 list[(*len)++] = ctree->name;
6782 break;
6783 case XML_ELEMENT_CONTENT_SEQ:
6784 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6785 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6786 break;
6787 case XML_ELEMENT_CONTENT_OR:
6788 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6789 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6790 break;
6791 }
6792
6793 return(*len);
6794}
6795
William M. Brack9333cc22004-06-24 08:33:40 +00006796/*
6797 * Dummy function to suppress messages while we try out valid elements
6798 */
6799static void xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
6800 const char *msg ATTRIBUTE_UNUSED, ...) {
6801 return;
6802}
6803
Owen Taylor3473f882001-02-23 17:55:21 +00006804/**
6805 * xmlValidGetValidElements:
6806 * @prev: an element to insert after
6807 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006808 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006809 * @max: the size of the array
6810 *
6811 * This function returns the list of authorized children to insert
6812 * within an existing tree while respecting the validity constraints
6813 * forced by the Dtd. The insertion point is defined using @prev and
6814 * @next in the following ways:
6815 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6816 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6817 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6818 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6819 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6820 *
6821 * pointers to the element names are inserted at the beginning of the array
6822 * and do not need to be freed.
6823 *
6824 * returns the number of element in the list, or -1 in case of error. If
6825 * the function returns the value @max the caller is invited to grow the
6826 * receiving array and retry.
6827 */
6828
6829int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006830xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006831 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006832 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006833 int nb_valid_elements = 0;
6834 const xmlChar *elements[256];
6835 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006836 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006837
6838 xmlNode *ref_node;
6839 xmlNode *parent;
6840 xmlNode *test_node;
6841
6842 xmlNode *prev_next;
6843 xmlNode *next_prev;
6844 xmlNode *parent_childs;
6845 xmlNode *parent_last;
6846
6847 xmlElement *element_desc;
6848
6849 if (prev == NULL && next == NULL)
6850 return(-1);
6851
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006852 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006853 if (max <= 0) return(-1);
6854
William M. Brack9333cc22004-06-24 08:33:40 +00006855 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6856 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6857
Owen Taylor3473f882001-02-23 17:55:21 +00006858 nb_valid_elements = 0;
6859 ref_node = prev ? prev : next;
6860 parent = ref_node->parent;
6861
6862 /*
6863 * Retrieves the parent element declaration
6864 */
6865 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6866 parent->name);
6867 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6868 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6869 parent->name);
6870 if (element_desc == NULL) return(-1);
6871
6872 /*
6873 * Do a backup of the current tree structure
6874 */
6875 prev_next = prev ? prev->next : NULL;
6876 next_prev = next ? next->prev : NULL;
6877 parent_childs = parent->children;
6878 parent_last = parent->last;
6879
6880 /*
6881 * Creates a dummy node and insert it into the tree
6882 */
Daniel Veillard95ddcd32004-10-26 21:53:55 +00006883 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006884 test_node->parent = parent;
6885 test_node->prev = prev;
6886 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006887 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006888
6889 if (prev) prev->next = test_node;
6890 else parent->children = test_node;
6891
6892 if (next) next->prev = test_node;
6893 else parent->last = test_node;
6894
6895 /*
6896 * Insert each potential child node and check if the parent is
6897 * still valid
6898 */
6899 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6900 elements, &nb_elements, 256);
6901
6902 for (i = 0;i < nb_elements;i++) {
6903 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006904 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006905 int j;
6906
6907 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006908 if (xmlStrEqual(elements[i], names[j])) break;
6909 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00006910 if (nb_valid_elements >= max) break;
6911 }
6912 }
6913
6914 /*
6915 * Restore the tree structure
6916 */
6917 if (prev) prev->next = prev_next;
6918 if (next) next->prev = next_prev;
6919 parent->children = parent_childs;
6920 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006921
6922 /*
6923 * Free up the dummy node
6924 */
6925 test_node->name = name;
6926 xmlFreeNode(test_node);
6927
Owen Taylor3473f882001-02-23 17:55:21 +00006928 return(nb_valid_elements);
6929}
Daniel Veillard4432df22003-09-28 18:58:27 +00006930#endif /* LIBXML_VALID_ENABLED */
6931