blob: 2ce83b13961f954815022e65d6337b3d9ecf0bfe [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;
62 pctxt = ctxt->userData;
63 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000064 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000065 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000066 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000067 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
68 "Memory allocation failed : %s\n", extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000069 else
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, NULL, NULL, NULL, 0, 0,
73 "Memory allocation failed\n");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000074}
75
76/**
77 * xmlErrValid:
78 * @ctxt: an XML validation parser context
Daniel Veillardbb5abab2003-10-03 22:21:51 +000079 * @error: the error number
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000080 * @extra: extra informations
81 *
82 * Handle a validation error
83 */
84static void
Daniel Veillardf88d8cf2003-12-08 10:25:02 +000085xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000086 const char *msg, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000087{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000088 xmlGenericErrorFunc channel = NULL;
89 xmlParserCtxtPtr pctxt = NULL;
90 void *data = NULL;
91
92 if (ctxt != NULL) {
93 channel = ctxt->error;
94 data = ctxt->userData;
95 pctxt = ctxt->userData;
96 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000097 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000098 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000099 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000100 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
101 msg, extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000102 else
Daniel Veillard73000572003-10-11 11:26:42 +0000103 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000104 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000105 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
106 msg);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000107}
108
Daniel Veillardf54cd532004-02-25 11:52:31 +0000109#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
110/**
111 * xmlErrValidNode:
112 * @ctxt: an XML validation parser context
113 * @node: the node raising the error
114 * @error: the error number
115 * @str1: extra informations
116 * @str2: extra informations
117 * @str3: extra informations
118 *
119 * Handle a validation error, provide contextual informations
120 */
121static void
122xmlErrValidNode(xmlValidCtxtPtr ctxt,
123 xmlNodePtr node, xmlParserErrors error,
124 const char *msg, const xmlChar * str1,
125 const xmlChar * str2, const xmlChar * str3)
126{
127 xmlStructuredErrorFunc schannel = NULL;
128 xmlGenericErrorFunc channel = NULL;
129 xmlParserCtxtPtr pctxt = NULL;
130 void *data = NULL;
131
132 if (ctxt != NULL) {
133 channel = ctxt->error;
134 data = ctxt->userData;
135 pctxt = ctxt->userData;
136 }
137 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
138 XML_ERR_ERROR, NULL, 0,
139 (const char *) str1,
140 (const char *) str1,
141 (const char *) str3, 0, 0, msg, str1, str2, str3);
142}
143#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
144
Daniel Veillardd61e8fb2003-10-19 21:59:17 +0000145#ifdef LIBXML_VALID_ENABLED
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000146/**
147 * xmlErrValidNodeNr:
148 * @ctxt: an XML validation parser context
149 * @node: the node raising the error
150 * @error: the error number
151 * @str1: extra informations
152 * @int2: extra informations
153 * @str3: extra informations
154 *
155 * Handle a validation error, provide contextual informations
156 */
157static void
Daniel Veillard72b9e292003-10-28 15:44:17 +0000158xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000159 xmlNodePtr node, xmlParserErrors error,
160 const char *msg, const xmlChar * str1,
161 int int2, const xmlChar * str3)
162{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000163 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000164 xmlGenericErrorFunc channel = NULL;
165 xmlParserCtxtPtr pctxt = NULL;
166 void *data = NULL;
167
168 if (ctxt != NULL) {
169 channel = ctxt->error;
170 data = ctxt->userData;
171 pctxt = ctxt->userData;
172 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000173 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000174 XML_ERR_ERROR, NULL, 0,
175 (const char *) str1,
176 (const char *) str3,
177 NULL, int2, 0, msg, str1, int2, str3);
178}
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000179
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000180/**
181 * xmlErrValidWarning:
182 * @ctxt: an XML validation parser context
183 * @node: the node raising the error
184 * @error: the error number
William M. Brackedb65a72004-02-06 07:36:04 +0000185 * @str1: extra information
186 * @str2: extra information
187 * @str3: extra information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000188 *
William M. Brackedb65a72004-02-06 07:36:04 +0000189 * Handle a validation error, provide contextual information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000190 */
191static void
William M. Brackedb65a72004-02-06 07:36:04 +0000192xmlErrValidWarning(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000193 xmlNodePtr node, xmlParserErrors error,
194 const char *msg, const xmlChar * str1,
195 const xmlChar * str2, const xmlChar * str3)
196{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000197 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000198 xmlGenericErrorFunc channel = NULL;
199 xmlParserCtxtPtr pctxt = NULL;
200 void *data = NULL;
201
202 if (ctxt != NULL) {
203 channel = ctxt->error;
204 data = ctxt->userData;
205 pctxt = ctxt->userData;
206 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000207 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000208 XML_ERR_WARNING, NULL, 0,
209 (const char *) str1,
210 (const char *) str1,
211 (const char *) str3, 0, 0, msg, str1, str2, str3);
212}
213
214
Daniel Veillardea7751d2002-12-20 00:16:24 +0000215
216#ifdef LIBXML_REGEXP_ENABLED
217/*
218 * If regexp are enabled we can do continuous validation without the
219 * need of a tree to validate the content model. this is done in each
220 * callbacks.
221 * Each xmlValidState represent the validation state associated to the
222 * set of nodes currently open from the document root to the current element.
223 */
224
225
226typedef struct _xmlValidState {
227 xmlElementPtr elemDecl; /* pointer to the content model */
228 xmlNodePtr node; /* pointer to the current node */
229 xmlRegExecCtxtPtr exec; /* regexp runtime */
230} _xmlValidState;
231
232
233static int
234vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000235 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000236 ctxt->vstateMax = 10;
237 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
238 sizeof(ctxt->vstateTab[0]));
239 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000240 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000241 return(-1);
242 }
243 }
244
245 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000246 xmlValidState *tmp;
247
248 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
249 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
250 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000251 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000252 return(-1);
253 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000254 ctxt->vstateMax *= 2;
255 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000256 }
257 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
258 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
259 ctxt->vstateTab[ctxt->vstateNr].node = node;
260 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
261 if (elemDecl->contModel == NULL)
262 xmlValidBuildContentModel(ctxt, elemDecl);
263 if (elemDecl->contModel != NULL) {
264 ctxt->vstateTab[ctxt->vstateNr].exec =
265 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
266 } else {
267 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000268 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
269 XML_ERR_INTERNAL_ERROR,
270 "Failed to build content model regexp for %s\n",
271 node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000272 }
273 }
274 return(ctxt->vstateNr++);
275}
276
277static int
278vstateVPop(xmlValidCtxtPtr ctxt) {
279 xmlElementPtr elemDecl;
280
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000281 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000282 ctxt->vstateNr--;
283 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
284 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
285 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
286 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
287 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
288 }
289 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
290 if (ctxt->vstateNr >= 1)
291 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
292 else
293 ctxt->vstate = NULL;
294 return(ctxt->vstateNr);
295}
296
297#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000298/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000299 * If regexp are not enabled, it uses a home made algorithm less
300 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000301 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000302 * only restriction is on the deepness of the tree limited by the
303 * size of the occurs bitfield
304 *
305 * this is the content of a saved state for rollbacks
306 */
307
308#define ROLLBACK_OR 0
309#define ROLLBACK_PARENT 1
310
Daniel Veillardb44025c2001-10-11 22:55:55 +0000311typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000312 xmlElementContentPtr cont; /* pointer to the content model subtree */
313 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000314 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000315 unsigned char depth; /* current depth in the overall tree */
316 unsigned char state; /* ROLLBACK_XXX */
317} _xmlValidState;
318
Daniel Veillardfc57b412002-04-29 15:50:14 +0000319#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000320#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
321#define CONT ctxt->vstate->cont
322#define NODE ctxt->vstate->node
323#define DEPTH ctxt->vstate->depth
324#define OCCURS ctxt->vstate->occurs
325#define STATE ctxt->vstate->state
326
Daniel Veillard5344c602001-12-31 16:37:34 +0000327#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
328#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000329
Daniel Veillard5344c602001-12-31 16:37:34 +0000330#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
331#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000332
333static int
334vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
335 xmlNodePtr node, unsigned char depth, long occurs,
336 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000337 int i = ctxt->vstateNr - 1;
338
Daniel Veillard940492d2002-04-15 10:15:25 +0000339 if (ctxt->vstateNr > MAX_RECURSE) {
340 return(-1);
341 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000342 if (ctxt->vstateTab == NULL) {
343 ctxt->vstateMax = 8;
344 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
345 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
346 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000347 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000348 return(-1);
349 }
350 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000351 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000352 xmlValidState *tmp;
353
354 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
355 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
356 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000357 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000358 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000359 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000360 ctxt->vstateMax *= 2;
361 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000362 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000363 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000364 /*
365 * Don't push on the stack a state already here
366 */
367 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
368 (ctxt->vstateTab[i].node == node) &&
369 (ctxt->vstateTab[i].depth == depth) &&
370 (ctxt->vstateTab[i].occurs == occurs) &&
371 (ctxt->vstateTab[i].state == state))
372 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000373 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
374 ctxt->vstateTab[ctxt->vstateNr].node = node;
375 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
376 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
377 ctxt->vstateTab[ctxt->vstateNr].state = state;
378 return(ctxt->vstateNr++);
379}
380
381static int
382vstateVPop(xmlValidCtxtPtr ctxt) {
383 if (ctxt->vstateNr <= 1) return(-1);
384 ctxt->vstateNr--;
385 ctxt->vstate = &ctxt->vstateTab[0];
386 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
387 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
388 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
389 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
390 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
391 return(ctxt->vstateNr);
392}
393
Daniel Veillard118aed72002-09-24 14:13:13 +0000394#endif /* LIBXML_REGEXP_ENABLED */
395
Daniel Veillard1c732d22002-11-30 11:22:59 +0000396static int
397nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
398{
399 if (ctxt->nodeMax <= 0) {
400 ctxt->nodeMax = 4;
401 ctxt->nodeTab =
402 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
403 sizeof(ctxt->nodeTab[0]));
404 if (ctxt->nodeTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000405 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000406 ctxt->nodeMax = 0;
407 return (0);
408 }
409 }
410 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000411 xmlNodePtr *tmp;
412 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
413 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
414 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000415 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000416 return (0);
417 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000418 ctxt->nodeMax *= 2;
419 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000420 }
421 ctxt->nodeTab[ctxt->nodeNr] = value;
422 ctxt->node = value;
423 return (ctxt->nodeNr++);
424}
425static xmlNodePtr
426nodeVPop(xmlValidCtxtPtr ctxt)
427{
428 xmlNodePtr ret;
429
430 if (ctxt->nodeNr <= 0)
431 return (0);
432 ctxt->nodeNr--;
433 if (ctxt->nodeNr > 0)
434 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
435 else
436 ctxt->node = NULL;
437 ret = ctxt->nodeTab[ctxt->nodeNr];
438 ctxt->nodeTab[ctxt->nodeNr] = 0;
439 return (ret);
440}
Owen Taylor3473f882001-02-23 17:55:21 +0000441
Owen Taylor3473f882001-02-23 17:55:21 +0000442#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000443static void
444xmlValidPrintNode(xmlNodePtr cur) {
445 if (cur == NULL) {
446 xmlGenericError(xmlGenericErrorContext, "null");
447 return;
448 }
449 switch (cur->type) {
450 case XML_ELEMENT_NODE:
451 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
452 break;
453 case XML_TEXT_NODE:
454 xmlGenericError(xmlGenericErrorContext, "text ");
455 break;
456 case XML_CDATA_SECTION_NODE:
457 xmlGenericError(xmlGenericErrorContext, "cdata ");
458 break;
459 case XML_ENTITY_REF_NODE:
460 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
461 break;
462 case XML_PI_NODE:
463 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
464 break;
465 case XML_COMMENT_NODE:
466 xmlGenericError(xmlGenericErrorContext, "comment ");
467 break;
468 case XML_ATTRIBUTE_NODE:
469 xmlGenericError(xmlGenericErrorContext, "?attr? ");
470 break;
471 case XML_ENTITY_NODE:
472 xmlGenericError(xmlGenericErrorContext, "?ent? ");
473 break;
474 case XML_DOCUMENT_NODE:
475 xmlGenericError(xmlGenericErrorContext, "?doc? ");
476 break;
477 case XML_DOCUMENT_TYPE_NODE:
478 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
479 break;
480 case XML_DOCUMENT_FRAG_NODE:
481 xmlGenericError(xmlGenericErrorContext, "?frag? ");
482 break;
483 case XML_NOTATION_NODE:
484 xmlGenericError(xmlGenericErrorContext, "?nota? ");
485 break;
486 case XML_HTML_DOCUMENT_NODE:
487 xmlGenericError(xmlGenericErrorContext, "?html? ");
488 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000489#ifdef LIBXML_DOCB_ENABLED
490 case XML_DOCB_DOCUMENT_NODE:
491 xmlGenericError(xmlGenericErrorContext, "?docb? ");
492 break;
493#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000494 case XML_DTD_NODE:
495 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
496 break;
497 case XML_ELEMENT_DECL:
498 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
499 break;
500 case XML_ATTRIBUTE_DECL:
501 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
502 break;
503 case XML_ENTITY_DECL:
504 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
505 break;
506 case XML_NAMESPACE_DECL:
507 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
508 break;
509 case XML_XINCLUDE_START:
510 xmlGenericError(xmlGenericErrorContext, "incstart ");
511 break;
512 case XML_XINCLUDE_END:
513 xmlGenericError(xmlGenericErrorContext, "incend ");
514 break;
515 }
516}
517
518static void
519xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000520 if (cur == NULL)
521 xmlGenericError(xmlGenericErrorContext, "null ");
522 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000523 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000524 cur = cur->next;
525 }
526}
527
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000528static void
529xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000530 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000531
532 expr[0] = 0;
533 xmlGenericError(xmlGenericErrorContext, "valid: ");
534 xmlValidPrintNodeList(cur);
535 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000536 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000537 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
538}
539
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000540static void
541xmlValidDebugState(xmlValidStatePtr state) {
542 xmlGenericError(xmlGenericErrorContext, "(");
543 if (state->cont == NULL)
544 xmlGenericError(xmlGenericErrorContext, "null,");
545 else
546 switch (state->cont->type) {
547 case XML_ELEMENT_CONTENT_PCDATA:
548 xmlGenericError(xmlGenericErrorContext, "pcdata,");
549 break;
550 case XML_ELEMENT_CONTENT_ELEMENT:
551 xmlGenericError(xmlGenericErrorContext, "%s,",
552 state->cont->name);
553 break;
554 case XML_ELEMENT_CONTENT_SEQ:
555 xmlGenericError(xmlGenericErrorContext, "seq,");
556 break;
557 case XML_ELEMENT_CONTENT_OR:
558 xmlGenericError(xmlGenericErrorContext, "or,");
559 break;
560 }
561 xmlValidPrintNode(state->node);
562 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
563 state->depth, state->occurs, state->state);
564}
565
566static void
567xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
568 int i, j;
569
570 xmlGenericError(xmlGenericErrorContext, "state: ");
571 xmlValidDebugState(ctxt->vstate);
572 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
573 ctxt->vstateNr - 1);
574 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
575 xmlValidDebugState(&ctxt->vstateTab[j]);
576 xmlGenericError(xmlGenericErrorContext, "\n");
577}
578
579/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000580#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000581 *****/
582
583#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000584#define DEBUG_VALID_MSG(m) \
585 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
586
Owen Taylor3473f882001-02-23 17:55:21 +0000587#else
588#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000589#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000590#endif
591
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000592/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000593
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000594
Owen Taylor3473f882001-02-23 17:55:21 +0000595#define CHECK_DTD \
596 if (doc == NULL) return(0); \
597 else if ((doc->intSubset == NULL) && \
598 (doc->extSubset == NULL)) return(0)
599
Owen Taylor3473f882001-02-23 17:55:21 +0000600xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
601
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000602#ifdef LIBXML_REGEXP_ENABLED
603
604/************************************************************************
605 * *
606 * Content model validation based on the regexps *
607 * *
608 ************************************************************************/
609
610/**
611 * xmlValidBuildAContentModel:
612 * @content: the content model
613 * @ctxt: the schema parser context
614 * @name: the element name whose content is being built
615 *
616 * Generate the automata sequence needed for that type
617 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000618 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000619 */
620static int
621xmlValidBuildAContentModel(xmlElementContentPtr content,
622 xmlValidCtxtPtr ctxt,
623 const xmlChar *name) {
624 if (content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000625 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
626 "Found NULL content in content model of %s\n",
627 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000628 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000629 }
630 switch (content->type) {
631 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000632 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
633 "Found PCDATA in content model of %s\n",
634 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000635 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000636 break;
637 case XML_ELEMENT_CONTENT_ELEMENT: {
638 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000639 xmlChar fn[50];
640 xmlChar *fullname;
641
642 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
643 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000644 xmlVErrMemory(ctxt, "Building content model");
Daniel Veillardc00cda82003-04-07 10:22:39 +0000645 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000646 }
647
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000648 switch (content->ocur) {
649 case XML_ELEMENT_CONTENT_ONCE:
650 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000651 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000652 break;
653 case XML_ELEMENT_CONTENT_OPT:
654 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000655 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000656 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
657 break;
658 case XML_ELEMENT_CONTENT_PLUS:
659 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000660 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000661 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000662 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000663 break;
664 case XML_ELEMENT_CONTENT_MULT:
William M. Brack8b0cbb02004-04-17 13:31:06 +0000665 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
666 ctxt->state, NULL);
667 xmlAutomataNewTransition(ctxt->am,
668 ctxt->state, ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000669 break;
670 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000671 if ((fullname != fn) && (fullname != content->name))
672 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000673 break;
674 }
675 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000676 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000677 xmlElementContentOccur ocur;
678
679 /*
680 * Simply iterate over the content
681 */
682 oldstate = ctxt->state;
683 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000684 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
685 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
686 oldstate = ctxt->state;
687 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000688 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000689 xmlValidBuildAContentModel(content->c1, ctxt, name);
690 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000691 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
692 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
693 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000694 oldend = ctxt->state;
695 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000696 switch (ocur) {
697 case XML_ELEMENT_CONTENT_ONCE:
698 break;
699 case XML_ELEMENT_CONTENT_OPT:
700 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
701 break;
702 case XML_ELEMENT_CONTENT_MULT:
703 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000704 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000705 break;
706 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000707 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000708 break;
709 }
710 break;
711 }
712 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000713 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000714 xmlElementContentOccur ocur;
715
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000716 ocur = content->ocur;
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000717 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
718 (ocur == XML_ELEMENT_CONTENT_MULT)) {
719 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
720 ctxt->state, NULL);
721 }
722 oldstate = ctxt->state;
723 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000724
725 /*
726 * iterate over the subtypes and remerge the end with an
727 * epsilon transition
728 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000729 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000730 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000731 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000732 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000733 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000734 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
735 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000736 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000737 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000738 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
739 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000740 switch (ocur) {
741 case XML_ELEMENT_CONTENT_ONCE:
742 break;
743 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000744 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000745 break;
746 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000747 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
748 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000749 break;
750 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000751 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000752 break;
753 }
754 break;
755 }
756 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000757 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
758 "ContentModel broken for element %s\n",
759 (const char *) name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000760 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000761 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000762 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000763}
764/**
765 * xmlValidBuildContentModel:
766 * @ctxt: a validation context
767 * @elem: an element declaration node
768 *
769 * (Re)Build the automata associated to the content model of this
770 * element
771 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000772 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000773 */
774int
775xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000776
777 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000778 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000779 if (elem->type != XML_ELEMENT_DECL)
780 return(0);
781 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
782 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000783 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000784 if (elem->contModel != NULL) {
785 if (!xmlRegexpIsDeterminist(elem->contModel)) {
786 ctxt->valid = 0;
787 return(0);
788 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000789 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000790 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000791
792 ctxt->am = xmlNewAutomata();
793 if (ctxt->am == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000794 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
795 XML_ERR_INTERNAL_ERROR,
796 "Cannot create automata for element %s\n",
797 elem->name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000798 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000799 }
William M. Brack78637da2003-07-31 14:47:38 +0000800 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000801 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
802 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000803 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000804 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000805 char expr[5000];
806 expr[0] = 0;
807 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000808 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
809 XML_DTD_CONTENT_NOT_DETERMINIST,
810 "Content model of %s is not determinist: %s\n",
811 elem->name, BAD_CAST expr, NULL);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000812#ifdef DEBUG_REGEXP_ALGO
813 xmlRegexpPrint(stderr, elem->contModel);
814#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000815 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000816 ctxt->state = NULL;
817 xmlFreeAutomata(ctxt->am);
818 ctxt->am = NULL;
819 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000820 }
821 ctxt->state = NULL;
822 xmlFreeAutomata(ctxt->am);
823 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000824 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000825}
826
827#endif /* LIBXML_REGEXP_ENABLED */
828
Owen Taylor3473f882001-02-23 17:55:21 +0000829/****************************************************************
830 * *
831 * Util functions for data allocation/deallocation *
832 * *
833 ****************************************************************/
834
835/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000836 * xmlNewValidCtxt:
837 *
838 * Allocate a validation context structure.
839 *
840 * Returns NULL if not, otherwise the new validation context structure
841 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000842xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000843 xmlValidCtxtPtr ret;
844
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000845 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000846 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000847 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000848 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000849
850 (void) memset(ret, 0, sizeof (xmlValidCtxt));
851
852 return (ret);
853}
854
855/**
856 * xmlFreeValidCtxt:
857 * @cur: the validation context to free
858 *
859 * Free a validation context structure.
860 */
861void
862xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
863 xmlFree(cur);
864}
865
Daniel Veillard4432df22003-09-28 18:58:27 +0000866#endif /* LIBXML_VALID_ENABLED */
867
Daniel Veillarda37aab82003-06-09 09:10:36 +0000868/**
Owen Taylor3473f882001-02-23 17:55:21 +0000869 * xmlNewElementContent:
870 * @name: the subelement name or NULL
871 * @type: the type of element content decl
872 *
873 * Allocate an element content structure.
874 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000875 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000876 */
877xmlElementContentPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000878xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000879 xmlElementContentPtr ret;
880
881 switch(type) {
882 case XML_ELEMENT_CONTENT_ELEMENT:
883 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000884 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
885 "xmlNewElementContent : name == NULL !\n",
886 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000887 }
888 break;
889 case XML_ELEMENT_CONTENT_PCDATA:
890 case XML_ELEMENT_CONTENT_SEQ:
891 case XML_ELEMENT_CONTENT_OR:
892 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000893 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
894 "xmlNewElementContent : name != NULL !\n",
895 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000896 }
897 break;
898 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000899 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
900 "Internal: ELEMENT content corrupted invalid type\n",
901 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000902 return(NULL);
903 }
904 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
905 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000906 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000907 return(NULL);
908 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000909 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000910 ret->type = type;
911 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000912 if (name != NULL) {
913 xmlChar *prefix = NULL;
914 ret->name = xmlSplitQName2(name, &prefix);
915 if (ret->name == NULL)
916 ret->name = xmlStrdup(name);
917 ret->prefix = prefix;
918 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000919 ret->name = NULL;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000920 ret->prefix = NULL;
921 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000922 ret->c1 = ret->c2 = ret->parent = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000923 return(ret);
924}
925
926/**
927 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000928 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +0000929 *
930 * Build a copy of an element content description.
931 *
932 * Returns the new xmlElementContentPtr or NULL in case of error.
933 */
934xmlElementContentPtr
935xmlCopyElementContent(xmlElementContentPtr cur) {
936 xmlElementContentPtr ret;
937
938 if (cur == NULL) return(NULL);
939 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
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 Veillardbe480fb2001-11-08 23:36:42 +0000944 if (cur->prefix != NULL)
945 ret->prefix = xmlStrdup(cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000946 ret->ocur = cur->ocur;
947 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000948 if (ret->c1 != NULL)
949 ret->c1->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000950 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000951 if (ret->c2 != NULL)
952 ret->c2->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000953 return(ret);
954}
955
956/**
957 * xmlFreeElementContent:
958 * @cur: the element content tree to free
959 *
960 * Free an element content structure. This is a recursive call !
961 */
962void
963xmlFreeElementContent(xmlElementContentPtr cur) {
964 if (cur == NULL) return;
965 switch (cur->type) {
966 case XML_ELEMENT_CONTENT_PCDATA:
967 case XML_ELEMENT_CONTENT_ELEMENT:
968 case XML_ELEMENT_CONTENT_SEQ:
969 case XML_ELEMENT_CONTENT_OR:
970 break;
971 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000972 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
973 "Internal: ELEMENT content corrupted invalid type\n",
974 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000975 return;
976 }
977 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
978 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
979 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000980 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000981 xmlFree(cur);
982}
983
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000984#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000985/**
986 * xmlDumpElementContent:
987 * @buf: An XML buffer
988 * @content: An element table
989 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
990 *
991 * This will dump the content of the element table as an XML DTD definition
992 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000993static void
Owen Taylor3473f882001-02-23 17:55:21 +0000994xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
995 if (content == NULL) return;
996
997 if (glob) xmlBufferWriteChar(buf, "(");
998 switch (content->type) {
999 case XML_ELEMENT_CONTENT_PCDATA:
1000 xmlBufferWriteChar(buf, "#PCDATA");
1001 break;
1002 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001003 if (content->prefix != NULL) {
1004 xmlBufferWriteCHAR(buf, content->prefix);
1005 xmlBufferWriteChar(buf, ":");
1006 }
Owen Taylor3473f882001-02-23 17:55:21 +00001007 xmlBufferWriteCHAR(buf, content->name);
1008 break;
1009 case XML_ELEMENT_CONTENT_SEQ:
1010 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1011 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1012 xmlDumpElementContent(buf, content->c1, 1);
1013 else
1014 xmlDumpElementContent(buf, content->c1, 0);
1015 xmlBufferWriteChar(buf, " , ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001016 if ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1017 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
1018 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001019 xmlDumpElementContent(buf, content->c2, 1);
1020 else
1021 xmlDumpElementContent(buf, content->c2, 0);
1022 break;
1023 case XML_ELEMENT_CONTENT_OR:
1024 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1025 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1026 xmlDumpElementContent(buf, content->c1, 1);
1027 else
1028 xmlDumpElementContent(buf, content->c1, 0);
1029 xmlBufferWriteChar(buf, " | ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001030 if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1031 ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
1032 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001033 xmlDumpElementContent(buf, content->c2, 1);
1034 else
1035 xmlDumpElementContent(buf, content->c2, 0);
1036 break;
1037 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001038 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1039 "Internal: ELEMENT content corrupted invalid type\n",
1040 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001041 }
1042 if (glob)
1043 xmlBufferWriteChar(buf, ")");
1044 switch (content->ocur) {
1045 case XML_ELEMENT_CONTENT_ONCE:
1046 break;
1047 case XML_ELEMENT_CONTENT_OPT:
1048 xmlBufferWriteChar(buf, "?");
1049 break;
1050 case XML_ELEMENT_CONTENT_MULT:
1051 xmlBufferWriteChar(buf, "*");
1052 break;
1053 case XML_ELEMENT_CONTENT_PLUS:
1054 xmlBufferWriteChar(buf, "+");
1055 break;
1056 }
1057}
1058
1059/**
1060 * xmlSprintfElementContent:
1061 * @buf: an output buffer
1062 * @content: An element table
1063 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1064 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001065 * Deprecated, unsafe, use xmlSnprintfElementContent
1066 */
1067void
1068xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1069 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1070 int glob ATTRIBUTE_UNUSED) {
1071}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001072#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001073
1074/**
1075 * xmlSnprintfElementContent:
1076 * @buf: an output buffer
1077 * @size: the buffer size
1078 * @content: An element table
1079 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1080 *
Owen Taylor3473f882001-02-23 17:55:21 +00001081 * This will dump the content of the element content definition
1082 * Intended just for the debug routine
1083 */
1084void
Daniel Veillardd3d06722001-08-15 12:06:36 +00001085xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int glob) {
1086 int len;
1087
Owen Taylor3473f882001-02-23 17:55:21 +00001088 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001089 len = strlen(buf);
1090 if (size - len < 50) {
1091 if ((size - len > 4) && (buf[len - 1] != '.'))
1092 strcat(buf, " ...");
1093 return;
1094 }
Owen Taylor3473f882001-02-23 17:55:21 +00001095 if (glob) strcat(buf, "(");
1096 switch (content->type) {
1097 case XML_ELEMENT_CONTENT_PCDATA:
1098 strcat(buf, "#PCDATA");
1099 break;
1100 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001101 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001102 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001103 strcat(buf, " ...");
1104 return;
1105 }
1106 strcat(buf, (char *) content->prefix);
1107 strcat(buf, ":");
1108 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001109 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001110 strcat(buf, " ...");
1111 return;
1112 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001113 if (content->name != NULL)
1114 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001115 break;
1116 case XML_ELEMENT_CONTENT_SEQ:
1117 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1118 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001119 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001120 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001121 xmlSnprintfElementContent(buf, size, content->c1, 0);
1122 len = strlen(buf);
1123 if (size - len < 50) {
1124 if ((size - len > 4) && (buf[len - 1] != '.'))
1125 strcat(buf, " ...");
1126 return;
1127 }
Owen Taylor3473f882001-02-23 17:55:21 +00001128 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001129 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1130 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1131 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001132 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001133 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001134 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001135 break;
1136 case XML_ELEMENT_CONTENT_OR:
1137 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1138 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001139 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001140 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001141 xmlSnprintfElementContent(buf, size, content->c1, 0);
1142 len = strlen(buf);
1143 if (size - len < 50) {
1144 if ((size - len > 4) && (buf[len - 1] != '.'))
1145 strcat(buf, " ...");
1146 return;
1147 }
Owen Taylor3473f882001-02-23 17:55:21 +00001148 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001149 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1150 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1151 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001152 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001153 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001154 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001155 break;
1156 }
1157 if (glob)
1158 strcat(buf, ")");
1159 switch (content->ocur) {
1160 case XML_ELEMENT_CONTENT_ONCE:
1161 break;
1162 case XML_ELEMENT_CONTENT_OPT:
1163 strcat(buf, "?");
1164 break;
1165 case XML_ELEMENT_CONTENT_MULT:
1166 strcat(buf, "*");
1167 break;
1168 case XML_ELEMENT_CONTENT_PLUS:
1169 strcat(buf, "+");
1170 break;
1171 }
1172}
1173
1174/****************************************************************
1175 * *
1176 * Registration of DTD declarations *
1177 * *
1178 ****************************************************************/
1179
1180/**
1181 * xmlCreateElementTable:
1182 *
1183 * create and initialize an empty element hash table.
1184 *
1185 * Returns the xmlElementTablePtr just created or NULL in case of error.
1186 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001187static xmlElementTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001188xmlCreateElementTable(void) {
1189 return(xmlHashCreate(0));
1190}
1191
1192/**
1193 * xmlFreeElement:
1194 * @elem: An element
1195 *
1196 * Deallocate the memory used by an element definition
1197 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001198static void
Owen Taylor3473f882001-02-23 17:55:21 +00001199xmlFreeElement(xmlElementPtr elem) {
1200 if (elem == NULL) return;
1201 xmlUnlinkNode((xmlNodePtr) elem);
1202 xmlFreeElementContent(elem->content);
1203 if (elem->name != NULL)
1204 xmlFree((xmlChar *) elem->name);
1205 if (elem->prefix != NULL)
1206 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001207#ifdef LIBXML_REGEXP_ENABLED
1208 if (elem->contModel != NULL)
1209 xmlRegFreeRegexp(elem->contModel);
1210#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001211 xmlFree(elem);
1212}
1213
1214
1215/**
1216 * xmlAddElementDecl:
1217 * @ctxt: the validation context
1218 * @dtd: pointer to the DTD
1219 * @name: the entity name
1220 * @type: the element type
1221 * @content: the element content tree or NULL
1222 *
1223 * Register a new element declaration
1224 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001225 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001226 */
1227xmlElementPtr
William M. Brackedb65a72004-02-06 07:36:04 +00001228xmlAddElementDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001229 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001230 xmlElementTypeVal type,
1231 xmlElementContentPtr content) {
1232 xmlElementPtr ret;
1233 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001234 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001235 xmlChar *ns, *uqname;
1236
1237 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001238 return(NULL);
1239 }
1240 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001241 return(NULL);
1242 }
1243 switch (type) {
1244 case XML_ELEMENT_TYPE_EMPTY:
1245 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001246 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1247 "xmlAddElementDecl: content != NULL for EMPTY\n",
1248 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001249 return(NULL);
1250 }
1251 break;
1252 case XML_ELEMENT_TYPE_ANY:
1253 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001254 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1255 "xmlAddElementDecl: content != NULL for ANY\n",
1256 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001257 return(NULL);
1258 }
1259 break;
1260 case XML_ELEMENT_TYPE_MIXED:
1261 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001262 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1263 "xmlAddElementDecl: content == NULL for MIXED\n",
1264 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001265 return(NULL);
1266 }
1267 break;
1268 case XML_ELEMENT_TYPE_ELEMENT:
1269 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001270 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1271 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1272 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001273 return(NULL);
1274 }
1275 break;
1276 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001277 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1278 "Internal: ELEMENT decl corrupted invalid type\n",
1279 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001280 return(NULL);
1281 }
1282
1283 /*
1284 * check if name is a QName
1285 */
1286 uqname = xmlSplitQName2(name, &ns);
1287 if (uqname != NULL)
1288 name = uqname;
1289
1290 /*
1291 * Create the Element table if needed.
1292 */
1293 table = (xmlElementTablePtr) dtd->elements;
1294 if (table == NULL) {
1295 table = xmlCreateElementTable();
1296 dtd->elements = (void *) table;
1297 }
1298 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001299 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001300 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001301 if (uqname != NULL)
1302 xmlFree(uqname);
1303 if (ns != NULL)
1304 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001305 return(NULL);
1306 }
1307
Daniel Veillarda10efa82001-04-18 13:09:01 +00001308 /*
1309 * lookup old attributes inserted on an undefined element in the
1310 * internal subset.
1311 */
1312 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1313 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1314 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1315 oldAttributes = ret->attributes;
1316 ret->attributes = NULL;
1317 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1318 xmlFreeElement(ret);
1319 }
Owen Taylor3473f882001-02-23 17:55:21 +00001320 }
Owen Taylor3473f882001-02-23 17:55:21 +00001321
1322 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001323 * The element may already be present if one of its attribute
1324 * was registered first
1325 */
1326 ret = xmlHashLookup2(table, name, ns);
1327 if (ret != NULL) {
1328 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001329#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001330 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001331 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001332 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001333 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1334 "Redefinition of element %s\n",
1335 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001336#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001337 if (uqname != NULL)
1338 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001339 if (ns != NULL)
1340 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001341 return(NULL);
1342 }
1343 } else {
1344 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1345 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001346 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001347 if (uqname != NULL)
1348 xmlFree(uqname);
1349 if (ns != NULL)
1350 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001351 return(NULL);
1352 }
1353 memset(ret, 0, sizeof(xmlElement));
1354 ret->type = XML_ELEMENT_DECL;
1355
1356 /*
1357 * fill the structure.
1358 */
1359 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001360 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001361 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001362 if (uqname != NULL)
1363 xmlFree(uqname);
1364 if (ns != NULL)
1365 xmlFree(ns);
1366 xmlFree(ret);
1367 return(NULL);
1368 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001369 ret->prefix = ns;
1370
1371 /*
1372 * Validity Check:
1373 * Insertion must not fail
1374 */
1375 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001376#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001377 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001378 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001379 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001380 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1381 "Redefinition of element %s\n",
1382 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001383#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001384 xmlFreeElement(ret);
1385 if (uqname != NULL)
1386 xmlFree(uqname);
1387 return(NULL);
1388 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001389 /*
1390 * For new element, may have attributes from earlier
1391 * definition in internal subset
1392 */
1393 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001394 }
1395
1396 /*
1397 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001398 */
1399 ret->etype = type;
Owen Taylor3473f882001-02-23 17:55:21 +00001400 ret->content = xmlCopyElementContent(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001401
1402 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001403 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001404 */
1405 ret->parent = dtd;
1406 ret->doc = dtd->doc;
1407 if (dtd->last == NULL) {
1408 dtd->children = dtd->last = (xmlNodePtr) ret;
1409 } else {
1410 dtd->last->next = (xmlNodePtr) ret;
1411 ret->prev = dtd->last;
1412 dtd->last = (xmlNodePtr) ret;
1413 }
1414 if (uqname != NULL)
1415 xmlFree(uqname);
1416 return(ret);
1417}
1418
1419/**
1420 * xmlFreeElementTable:
1421 * @table: An element table
1422 *
1423 * Deallocate the memory used by an element hash table.
1424 */
1425void
1426xmlFreeElementTable(xmlElementTablePtr table) {
1427 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1428}
1429
Daniel Veillard652327a2003-09-29 18:02:38 +00001430#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001431/**
1432 * xmlCopyElement:
1433 * @elem: An element
1434 *
1435 * Build a copy of an element.
1436 *
1437 * Returns the new xmlElementPtr or NULL in case of error.
1438 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001439static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001440xmlCopyElement(xmlElementPtr elem) {
1441 xmlElementPtr cur;
1442
1443 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1444 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001445 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001446 return(NULL);
1447 }
1448 memset(cur, 0, sizeof(xmlElement));
1449 cur->type = XML_ELEMENT_DECL;
1450 cur->etype = elem->etype;
1451 if (elem->name != NULL)
1452 cur->name = xmlStrdup(elem->name);
1453 else
1454 cur->name = NULL;
1455 if (elem->prefix != NULL)
1456 cur->prefix = xmlStrdup(elem->prefix);
1457 else
1458 cur->prefix = NULL;
1459 cur->content = xmlCopyElementContent(elem->content);
1460 /* TODO : rebuild the attribute list on the copy */
1461 cur->attributes = NULL;
1462 return(cur);
1463}
1464
1465/**
1466 * xmlCopyElementTable:
1467 * @table: An element table
1468 *
1469 * Build a copy of an element table.
1470 *
1471 * Returns the new xmlElementTablePtr or NULL in case of error.
1472 */
1473xmlElementTablePtr
1474xmlCopyElementTable(xmlElementTablePtr table) {
1475 return((xmlElementTablePtr) xmlHashCopy(table,
1476 (xmlHashCopier) xmlCopyElement));
1477}
Daniel Veillard652327a2003-09-29 18:02:38 +00001478#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001479
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001480#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001481/**
1482 * xmlDumpElementDecl:
1483 * @buf: the XML buffer output
1484 * @elem: An element table
1485 *
1486 * This will dump the content of the element declaration as an XML
1487 * DTD definition
1488 */
1489void
1490xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1491 switch (elem->etype) {
1492 case XML_ELEMENT_TYPE_EMPTY:
1493 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001494 if (elem->prefix != NULL) {
1495 xmlBufferWriteCHAR(buf, elem->prefix);
1496 xmlBufferWriteChar(buf, ":");
1497 }
Owen Taylor3473f882001-02-23 17:55:21 +00001498 xmlBufferWriteCHAR(buf, elem->name);
1499 xmlBufferWriteChar(buf, " EMPTY>\n");
1500 break;
1501 case XML_ELEMENT_TYPE_ANY:
1502 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001503 if (elem->prefix != NULL) {
1504 xmlBufferWriteCHAR(buf, elem->prefix);
1505 xmlBufferWriteChar(buf, ":");
1506 }
Owen Taylor3473f882001-02-23 17:55:21 +00001507 xmlBufferWriteCHAR(buf, elem->name);
1508 xmlBufferWriteChar(buf, " ANY>\n");
1509 break;
1510 case XML_ELEMENT_TYPE_MIXED:
1511 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001512 if (elem->prefix != NULL) {
1513 xmlBufferWriteCHAR(buf, elem->prefix);
1514 xmlBufferWriteChar(buf, ":");
1515 }
Owen Taylor3473f882001-02-23 17:55:21 +00001516 xmlBufferWriteCHAR(buf, elem->name);
1517 xmlBufferWriteChar(buf, " ");
1518 xmlDumpElementContent(buf, elem->content, 1);
1519 xmlBufferWriteChar(buf, ">\n");
1520 break;
1521 case XML_ELEMENT_TYPE_ELEMENT:
1522 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001523 if (elem->prefix != NULL) {
1524 xmlBufferWriteCHAR(buf, elem->prefix);
1525 xmlBufferWriteChar(buf, ":");
1526 }
Owen Taylor3473f882001-02-23 17:55:21 +00001527 xmlBufferWriteCHAR(buf, elem->name);
1528 xmlBufferWriteChar(buf, " ");
1529 xmlDumpElementContent(buf, elem->content, 1);
1530 xmlBufferWriteChar(buf, ">\n");
1531 break;
1532 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001533 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1534 "Internal: ELEMENT struct corrupted invalid type\n",
1535 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001536 }
1537}
1538
1539/**
William M. Brack9e660592003-10-20 14:56:06 +00001540 * xmlDumpElementDeclScan:
1541 * @elem: An element table
1542 * @buf: the XML buffer output
1543 *
1544 * This routine is used by the hash scan function. It just reverses
1545 * the arguments.
1546 */
1547static void
1548xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1549 xmlDumpElementDecl(buf, elem);
1550}
1551
1552/**
Owen Taylor3473f882001-02-23 17:55:21 +00001553 * xmlDumpElementTable:
1554 * @buf: the XML buffer output
1555 * @table: An element table
1556 *
1557 * This will dump the content of the element table as an XML DTD definition
1558 */
1559void
1560xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00001561 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001562}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001563#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001564
1565/**
1566 * xmlCreateEnumeration:
1567 * @name: the enumeration name or NULL
1568 *
1569 * create and initialize an enumeration attribute node.
1570 *
1571 * Returns the xmlEnumerationPtr just created or NULL in case
1572 * of error.
1573 */
1574xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001575xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001576 xmlEnumerationPtr ret;
1577
1578 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1579 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001580 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001581 return(NULL);
1582 }
1583 memset(ret, 0, sizeof(xmlEnumeration));
1584
1585 if (name != NULL)
1586 ret->name = xmlStrdup(name);
1587 return(ret);
1588}
1589
1590/**
1591 * xmlFreeEnumeration:
1592 * @cur: the tree to free.
1593 *
1594 * free an enumeration attribute node (recursive).
1595 */
1596void
1597xmlFreeEnumeration(xmlEnumerationPtr cur) {
1598 if (cur == NULL) return;
1599
1600 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1601
1602 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001603 xmlFree(cur);
1604}
1605
Daniel Veillard652327a2003-09-29 18:02:38 +00001606#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001607/**
1608 * xmlCopyEnumeration:
1609 * @cur: the tree to copy.
1610 *
1611 * Copy an enumeration attribute node (recursive).
1612 *
1613 * Returns the xmlEnumerationPtr just created or NULL in case
1614 * of error.
1615 */
1616xmlEnumerationPtr
1617xmlCopyEnumeration(xmlEnumerationPtr cur) {
1618 xmlEnumerationPtr ret;
1619
1620 if (cur == NULL) return(NULL);
1621 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1622
1623 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1624 else ret->next = NULL;
1625
1626 return(ret);
1627}
Daniel Veillard652327a2003-09-29 18:02:38 +00001628#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001629
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001630#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001631/**
1632 * xmlDumpEnumeration:
1633 * @buf: the XML buffer output
1634 * @enum: An enumeration
1635 *
1636 * This will dump the content of the enumeration
1637 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001638static void
Owen Taylor3473f882001-02-23 17:55:21 +00001639xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1640 if (cur == NULL) return;
1641
1642 xmlBufferWriteCHAR(buf, cur->name);
1643 if (cur->next == NULL)
1644 xmlBufferWriteChar(buf, ")");
1645 else {
1646 xmlBufferWriteChar(buf, " | ");
1647 xmlDumpEnumeration(buf, cur->next);
1648 }
1649}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001650#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001651
1652/**
1653 * xmlCreateAttributeTable:
1654 *
1655 * create and initialize an empty attribute hash table.
1656 *
1657 * Returns the xmlAttributeTablePtr just created or NULL in case
1658 * of error.
1659 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001660static xmlAttributeTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001661xmlCreateAttributeTable(void) {
1662 return(xmlHashCreate(0));
1663}
1664
Daniel Veillard4432df22003-09-28 18:58:27 +00001665#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001666/**
1667 * xmlScanAttributeDeclCallback:
1668 * @attr: the attribute decl
1669 * @list: the list to update
1670 *
1671 * Callback called by xmlScanAttributeDecl when a new attribute
1672 * has to be entered in the list.
1673 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001674static void
Owen Taylor3473f882001-02-23 17:55:21 +00001675xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001676 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001677 attr->nexth = *list;
1678 *list = attr;
1679}
1680
1681/**
1682 * xmlScanAttributeDecl:
1683 * @dtd: pointer to the DTD
1684 * @elem: the element name
1685 *
1686 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001687 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001688 *
1689 * Returns the pointer to the first attribute decl in the chain,
1690 * possibly NULL.
1691 */
1692xmlAttributePtr
1693xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1694 xmlAttributePtr ret = NULL;
1695 xmlAttributeTablePtr table;
1696
1697 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001698 return(NULL);
1699 }
1700 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001701 return(NULL);
1702 }
1703 table = (xmlAttributeTablePtr) dtd->attributes;
1704 if (table == NULL)
1705 return(NULL);
1706
1707 /* WRONG !!! */
1708 xmlHashScan3(table, NULL, NULL, elem,
1709 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1710 return(ret);
1711}
1712
1713/**
1714 * xmlScanIDAttributeDecl:
1715 * @ctxt: the validation context
1716 * @elem: the element name
1717 *
1718 * Verify that the element don't have too many ID attributes
1719 * declared.
1720 *
1721 * Returns the number of ID attributes found.
1722 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001723static int
Owen Taylor3473f882001-02-23 17:55:21 +00001724xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1725 xmlAttributePtr cur;
1726 int ret = 0;
1727
1728 if (elem == NULL) return(0);
1729 cur = elem->attributes;
1730 while (cur != NULL) {
1731 if (cur->atype == XML_ATTRIBUTE_ID) {
1732 ret ++;
1733 if (ret > 1)
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001734 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001735 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001736 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001737 }
1738 cur = cur->nexth;
1739 }
1740 return(ret);
1741}
Daniel Veillard4432df22003-09-28 18:58:27 +00001742#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001743
1744/**
1745 * xmlFreeAttribute:
1746 * @elem: An attribute
1747 *
1748 * Deallocate the memory used by an attribute definition
1749 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001750static void
Owen Taylor3473f882001-02-23 17:55:21 +00001751xmlFreeAttribute(xmlAttributePtr attr) {
1752 if (attr == NULL) return;
1753 xmlUnlinkNode((xmlNodePtr) attr);
1754 if (attr->tree != NULL)
1755 xmlFreeEnumeration(attr->tree);
1756 if (attr->elem != NULL)
1757 xmlFree((xmlChar *) attr->elem);
1758 if (attr->name != NULL)
1759 xmlFree((xmlChar *) attr->name);
1760 if (attr->defaultValue != NULL)
1761 xmlFree((xmlChar *) attr->defaultValue);
1762 if (attr->prefix != NULL)
1763 xmlFree((xmlChar *) attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001764 xmlFree(attr);
1765}
1766
1767
1768/**
1769 * xmlAddAttributeDecl:
1770 * @ctxt: the validation context
1771 * @dtd: pointer to the DTD
1772 * @elem: the element name
1773 * @name: the attribute name
1774 * @ns: the attribute namespace prefix
1775 * @type: the attribute type
1776 * @def: the attribute default type
1777 * @defaultValue: the attribute default value
1778 * @tree: if it's an enumeration, the associated list
1779 *
1780 * Register a new attribute declaration
1781 * Note that @tree becomes the ownership of the DTD
1782 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001783 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001784 */
1785xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001786xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001787 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001788 const xmlChar *name, const xmlChar *ns,
1789 xmlAttributeType type, xmlAttributeDefault def,
1790 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1791 xmlAttributePtr ret;
1792 xmlAttributeTablePtr table;
1793 xmlElementPtr elemDef;
1794
1795 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001796 xmlFreeEnumeration(tree);
1797 return(NULL);
1798 }
1799 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001800 xmlFreeEnumeration(tree);
1801 return(NULL);
1802 }
1803 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001804 xmlFreeEnumeration(tree);
1805 return(NULL);
1806 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001807
Daniel Veillard4432df22003-09-28 18:58:27 +00001808#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001809 /*
1810 * Check the type and possibly the default value.
1811 */
1812 switch (type) {
1813 case XML_ATTRIBUTE_CDATA:
1814 break;
1815 case XML_ATTRIBUTE_ID:
1816 break;
1817 case XML_ATTRIBUTE_IDREF:
1818 break;
1819 case XML_ATTRIBUTE_IDREFS:
1820 break;
1821 case XML_ATTRIBUTE_ENTITY:
1822 break;
1823 case XML_ATTRIBUTE_ENTITIES:
1824 break;
1825 case XML_ATTRIBUTE_NMTOKEN:
1826 break;
1827 case XML_ATTRIBUTE_NMTOKENS:
1828 break;
1829 case XML_ATTRIBUTE_ENUMERATION:
1830 break;
1831 case XML_ATTRIBUTE_NOTATION:
1832 break;
1833 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001834 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1835 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1836 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001837 xmlFreeEnumeration(tree);
1838 return(NULL);
1839 }
1840 if ((defaultValue != NULL) &&
1841 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001842 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1843 "Attribute %s of %s: invalid default value\n",
1844 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00001845 defaultValue = NULL;
Daniel Veillardd01fd3e2002-02-18 22:27:47 +00001846 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001847 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001848#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001849
1850 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001851 * Check first that an attribute defined in the external subset wasn't
1852 * already defined in the internal subset
1853 */
1854 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1855 (dtd->doc->intSubset != NULL) &&
1856 (dtd->doc->intSubset->attributes != NULL)) {
1857 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1858 if (ret != NULL)
1859 return(NULL);
1860 }
1861
1862 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001863 * Create the Attribute table if needed.
1864 */
1865 table = (xmlAttributeTablePtr) dtd->attributes;
1866 if (table == NULL) {
1867 table = xmlCreateAttributeTable();
1868 dtd->attributes = (void *) table;
1869 }
1870 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001871 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001872 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001873 return(NULL);
1874 }
1875
1876
1877 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1878 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001879 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001880 return(NULL);
1881 }
1882 memset(ret, 0, sizeof(xmlAttribute));
1883 ret->type = XML_ATTRIBUTE_DECL;
1884
1885 /*
1886 * fill the structure.
1887 */
1888 ret->atype = type;
1889 ret->name = xmlStrdup(name);
1890 ret->prefix = xmlStrdup(ns);
1891 ret->elem = xmlStrdup(elem);
1892 ret->def = def;
1893 ret->tree = tree;
1894 if (defaultValue != NULL)
1895 ret->defaultValue = xmlStrdup(defaultValue);
1896
1897 /*
1898 * Validity Check:
1899 * Search the DTD for previous declarations of the ATTLIST
1900 */
1901 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001902#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001903 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001904 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00001905 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001906 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00001907 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001908 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001909#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001910 xmlFreeAttribute(ret);
1911 return(NULL);
1912 }
1913
1914 /*
1915 * Validity Check:
1916 * Multiple ID per element
1917 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001918 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001919 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00001920
Daniel Veillard4432df22003-09-28 18:58:27 +00001921#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001922 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00001923 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001924 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00001925 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001926 elem, name, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00001927 ctxt->valid = 0;
1928 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001929#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00001930
Daniel Veillard48da9102001-08-07 01:10:10 +00001931 /*
1932 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001933 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00001934 */
1935 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1936 ((ret->prefix != NULL &&
1937 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1938 ret->nexth = elemDef->attributes;
1939 elemDef->attributes = ret;
1940 } else {
1941 xmlAttributePtr tmp = elemDef->attributes;
1942
1943 while ((tmp != NULL) &&
1944 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1945 ((ret->prefix != NULL &&
1946 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1947 if (tmp->nexth == NULL)
1948 break;
1949 tmp = tmp->nexth;
1950 }
1951 if (tmp != NULL) {
1952 ret->nexth = tmp->nexth;
1953 tmp->nexth = ret;
1954 } else {
1955 ret->nexth = elemDef->attributes;
1956 elemDef->attributes = ret;
1957 }
1958 }
Owen Taylor3473f882001-02-23 17:55:21 +00001959 }
1960
1961 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001962 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001963 */
1964 ret->parent = dtd;
1965 ret->doc = dtd->doc;
1966 if (dtd->last == NULL) {
1967 dtd->children = dtd->last = (xmlNodePtr) ret;
1968 } else {
1969 dtd->last->next = (xmlNodePtr) ret;
1970 ret->prev = dtd->last;
1971 dtd->last = (xmlNodePtr) ret;
1972 }
1973 return(ret);
1974}
1975
1976/**
1977 * xmlFreeAttributeTable:
1978 * @table: An attribute table
1979 *
1980 * Deallocate the memory used by an entities hash table.
1981 */
1982void
1983xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1984 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
1985}
1986
Daniel Veillard652327a2003-09-29 18:02:38 +00001987#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001988/**
1989 * xmlCopyAttribute:
1990 * @attr: An attribute
1991 *
1992 * Build a copy of an attribute.
1993 *
1994 * Returns the new xmlAttributePtr or NULL in case of error.
1995 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001996static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001997xmlCopyAttribute(xmlAttributePtr attr) {
1998 xmlAttributePtr cur;
1999
2000 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2001 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002002 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002003 return(NULL);
2004 }
2005 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00002006 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00002007 cur->atype = attr->atype;
2008 cur->def = attr->def;
2009 cur->tree = xmlCopyEnumeration(attr->tree);
2010 if (attr->elem != NULL)
2011 cur->elem = xmlStrdup(attr->elem);
2012 if (attr->name != NULL)
2013 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002014 if (attr->prefix != NULL)
2015 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002016 if (attr->defaultValue != NULL)
2017 cur->defaultValue = xmlStrdup(attr->defaultValue);
2018 return(cur);
2019}
2020
2021/**
2022 * xmlCopyAttributeTable:
2023 * @table: An attribute table
2024 *
2025 * Build a copy of an attribute table.
2026 *
2027 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2028 */
2029xmlAttributeTablePtr
2030xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2031 return((xmlAttributeTablePtr) xmlHashCopy(table,
2032 (xmlHashCopier) xmlCopyAttribute));
2033}
Daniel Veillard652327a2003-09-29 18:02:38 +00002034#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002035
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002036#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002037/**
2038 * xmlDumpAttributeDecl:
2039 * @buf: the XML buffer output
2040 * @attr: An attribute declaration
2041 *
2042 * This will dump the content of the attribute declaration as an XML
2043 * DTD definition
2044 */
2045void
2046xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2047 xmlBufferWriteChar(buf, "<!ATTLIST ");
2048 xmlBufferWriteCHAR(buf, attr->elem);
2049 xmlBufferWriteChar(buf, " ");
2050 if (attr->prefix != NULL) {
2051 xmlBufferWriteCHAR(buf, attr->prefix);
2052 xmlBufferWriteChar(buf, ":");
2053 }
2054 xmlBufferWriteCHAR(buf, attr->name);
2055 switch (attr->atype) {
2056 case XML_ATTRIBUTE_CDATA:
2057 xmlBufferWriteChar(buf, " CDATA");
2058 break;
2059 case XML_ATTRIBUTE_ID:
2060 xmlBufferWriteChar(buf, " ID");
2061 break;
2062 case XML_ATTRIBUTE_IDREF:
2063 xmlBufferWriteChar(buf, " IDREF");
2064 break;
2065 case XML_ATTRIBUTE_IDREFS:
2066 xmlBufferWriteChar(buf, " IDREFS");
2067 break;
2068 case XML_ATTRIBUTE_ENTITY:
2069 xmlBufferWriteChar(buf, " ENTITY");
2070 break;
2071 case XML_ATTRIBUTE_ENTITIES:
2072 xmlBufferWriteChar(buf, " ENTITIES");
2073 break;
2074 case XML_ATTRIBUTE_NMTOKEN:
2075 xmlBufferWriteChar(buf, " NMTOKEN");
2076 break;
2077 case XML_ATTRIBUTE_NMTOKENS:
2078 xmlBufferWriteChar(buf, " NMTOKENS");
2079 break;
2080 case XML_ATTRIBUTE_ENUMERATION:
2081 xmlBufferWriteChar(buf, " (");
2082 xmlDumpEnumeration(buf, attr->tree);
2083 break;
2084 case XML_ATTRIBUTE_NOTATION:
2085 xmlBufferWriteChar(buf, " NOTATION (");
2086 xmlDumpEnumeration(buf, attr->tree);
2087 break;
2088 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002089 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2090 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2091 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002092 }
2093 switch (attr->def) {
2094 case XML_ATTRIBUTE_NONE:
2095 break;
2096 case XML_ATTRIBUTE_REQUIRED:
2097 xmlBufferWriteChar(buf, " #REQUIRED");
2098 break;
2099 case XML_ATTRIBUTE_IMPLIED:
2100 xmlBufferWriteChar(buf, " #IMPLIED");
2101 break;
2102 case XML_ATTRIBUTE_FIXED:
2103 xmlBufferWriteChar(buf, " #FIXED");
2104 break;
2105 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002106 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2107 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2108 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002109 }
2110 if (attr->defaultValue != NULL) {
2111 xmlBufferWriteChar(buf, " ");
2112 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2113 }
2114 xmlBufferWriteChar(buf, ">\n");
2115}
2116
2117/**
William M. Brack9e660592003-10-20 14:56:06 +00002118 * xmlDumpAttributeDeclScan:
2119 * @attr: An attribute declaration
2120 * @buf: the XML buffer output
2121 *
2122 * This is used with the hash scan function - just reverses arguments
2123 */
2124static void
2125xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2126 xmlDumpAttributeDecl(buf, attr);
2127}
2128
2129/**
Owen Taylor3473f882001-02-23 17:55:21 +00002130 * xmlDumpAttributeTable:
2131 * @buf: the XML buffer output
2132 * @table: An attribute table
2133 *
2134 * This will dump the content of the attribute table as an XML DTD definition
2135 */
2136void
2137xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002138 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002139}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002140#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002141
2142/************************************************************************
2143 * *
2144 * NOTATIONs *
2145 * *
2146 ************************************************************************/
2147/**
2148 * xmlCreateNotationTable:
2149 *
2150 * create and initialize an empty notation hash table.
2151 *
2152 * Returns the xmlNotationTablePtr just created or NULL in case
2153 * of error.
2154 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002155static xmlNotationTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002156xmlCreateNotationTable(void) {
2157 return(xmlHashCreate(0));
2158}
2159
2160/**
2161 * xmlFreeNotation:
2162 * @not: A notation
2163 *
2164 * Deallocate the memory used by an notation definition
2165 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002166static void
Owen Taylor3473f882001-02-23 17:55:21 +00002167xmlFreeNotation(xmlNotationPtr nota) {
2168 if (nota == NULL) return;
2169 if (nota->name != NULL)
2170 xmlFree((xmlChar *) nota->name);
2171 if (nota->PublicID != NULL)
2172 xmlFree((xmlChar *) nota->PublicID);
2173 if (nota->SystemID != NULL)
2174 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002175 xmlFree(nota);
2176}
2177
2178
2179/**
2180 * xmlAddNotationDecl:
2181 * @dtd: pointer to the DTD
2182 * @ctxt: the validation context
2183 * @name: the entity name
2184 * @PublicID: the public identifier or NULL
2185 * @SystemID: the system identifier or NULL
2186 *
2187 * Register a new notation declaration
2188 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002189 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002190 */
2191xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002192xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002193 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002194 const xmlChar *PublicID, const xmlChar *SystemID) {
2195 xmlNotationPtr ret;
2196 xmlNotationTablePtr table;
2197
2198 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002199 return(NULL);
2200 }
2201 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002202 return(NULL);
2203 }
2204 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002205 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002206 }
2207
2208 /*
2209 * Create the Notation table if needed.
2210 */
2211 table = (xmlNotationTablePtr) dtd->notations;
2212 if (table == NULL)
2213 dtd->notations = table = xmlCreateNotationTable();
2214 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002215 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002216 "xmlAddNotationDecl: Table creation failed!\n");
2217 return(NULL);
2218 }
2219
2220 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2221 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002222 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002223 return(NULL);
2224 }
2225 memset(ret, 0, sizeof(xmlNotation));
2226
2227 /*
2228 * fill the structure.
2229 */
2230 ret->name = xmlStrdup(name);
2231 if (SystemID != NULL)
2232 ret->SystemID = xmlStrdup(SystemID);
2233 if (PublicID != NULL)
2234 ret->PublicID = xmlStrdup(PublicID);
2235
2236 /*
2237 * Validity Check:
2238 * Check the DTD for previous declarations of the ATTLIST
2239 */
2240 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002241#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002242 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2243 "xmlAddNotationDecl: %s already defined\n",
2244 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002245#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002246 xmlFreeNotation(ret);
2247 return(NULL);
2248 }
2249 return(ret);
2250}
2251
2252/**
2253 * xmlFreeNotationTable:
2254 * @table: An notation table
2255 *
2256 * Deallocate the memory used by an entities hash table.
2257 */
2258void
2259xmlFreeNotationTable(xmlNotationTablePtr table) {
2260 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2261}
2262
Daniel Veillard652327a2003-09-29 18:02:38 +00002263#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002264/**
2265 * xmlCopyNotation:
2266 * @nota: A notation
2267 *
2268 * Build a copy of a notation.
2269 *
2270 * Returns the new xmlNotationPtr or NULL in case of error.
2271 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002272static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002273xmlCopyNotation(xmlNotationPtr nota) {
2274 xmlNotationPtr cur;
2275
2276 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2277 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002278 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002279 return(NULL);
2280 }
2281 if (nota->name != NULL)
2282 cur->name = xmlStrdup(nota->name);
2283 else
2284 cur->name = NULL;
2285 if (nota->PublicID != NULL)
2286 cur->PublicID = xmlStrdup(nota->PublicID);
2287 else
2288 cur->PublicID = NULL;
2289 if (nota->SystemID != NULL)
2290 cur->SystemID = xmlStrdup(nota->SystemID);
2291 else
2292 cur->SystemID = NULL;
2293 return(cur);
2294}
2295
2296/**
2297 * xmlCopyNotationTable:
2298 * @table: A notation table
2299 *
2300 * Build a copy of a notation table.
2301 *
2302 * Returns the new xmlNotationTablePtr or NULL in case of error.
2303 */
2304xmlNotationTablePtr
2305xmlCopyNotationTable(xmlNotationTablePtr table) {
2306 return((xmlNotationTablePtr) xmlHashCopy(table,
2307 (xmlHashCopier) xmlCopyNotation));
2308}
Daniel Veillard652327a2003-09-29 18:02:38 +00002309#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002310
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002311#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002312/**
2313 * xmlDumpNotationDecl:
2314 * @buf: the XML buffer output
2315 * @nota: A notation declaration
2316 *
2317 * This will dump the content the notation declaration as an XML DTD definition
2318 */
2319void
2320xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2321 xmlBufferWriteChar(buf, "<!NOTATION ");
2322 xmlBufferWriteCHAR(buf, nota->name);
2323 if (nota->PublicID != NULL) {
2324 xmlBufferWriteChar(buf, " PUBLIC ");
2325 xmlBufferWriteQuotedString(buf, nota->PublicID);
2326 if (nota->SystemID != NULL) {
2327 xmlBufferWriteChar(buf, " ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002328 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002329 }
2330 } else {
2331 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002332 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002333 }
2334 xmlBufferWriteChar(buf, " >\n");
2335}
2336
2337/**
William M. Brack9e660592003-10-20 14:56:06 +00002338 * xmlDumpNotationDeclScan:
2339 * @nota: A notation declaration
2340 * @buf: the XML buffer output
2341 *
2342 * This is called with the hash scan function, and just reverses args
2343 */
2344static void
2345xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2346 xmlDumpNotationDecl(buf, nota);
2347}
2348
2349/**
Owen Taylor3473f882001-02-23 17:55:21 +00002350 * xmlDumpNotationTable:
2351 * @buf: the XML buffer output
2352 * @table: A notation table
2353 *
2354 * This will dump the content of the notation table as an XML DTD definition
2355 */
2356void
2357xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002358 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002359}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002360#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002361
2362/************************************************************************
2363 * *
2364 * IDs *
2365 * *
2366 ************************************************************************/
2367/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002368 * DICT_FREE:
2369 * @str: a string
2370 *
2371 * Free a string if it is not owned by the "dict" dictionnary in the
2372 * current scope
2373 */
2374#define DICT_FREE(str) \
2375 if ((str) && ((!dict) || \
2376 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2377 xmlFree((char *)(str));
2378
2379/**
Owen Taylor3473f882001-02-23 17:55:21 +00002380 * xmlCreateIDTable:
2381 *
2382 * create and initialize an empty id hash table.
2383 *
2384 * Returns the xmlIDTablePtr just created or NULL in case
2385 * of error.
2386 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002387static xmlIDTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002388xmlCreateIDTable(void) {
2389 return(xmlHashCreate(0));
2390}
2391
2392/**
2393 * xmlFreeID:
2394 * @not: A id
2395 *
2396 * Deallocate the memory used by an id definition
2397 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002398static void
Owen Taylor3473f882001-02-23 17:55:21 +00002399xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002400 xmlDictPtr dict = NULL;
2401
Owen Taylor3473f882001-02-23 17:55:21 +00002402 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002403
2404 if (id->doc != NULL)
2405 dict = id->doc->dict;
2406
Owen Taylor3473f882001-02-23 17:55:21 +00002407 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002408 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002409 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002410 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002411 xmlFree(id);
2412}
2413
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002414
Owen Taylor3473f882001-02-23 17:55:21 +00002415/**
2416 * xmlAddID:
2417 * @ctxt: the validation context
2418 * @doc: pointer to the document
2419 * @value: the value name
2420 * @attr: the attribute holding the ID
2421 *
2422 * Register a new id declaration
2423 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002424 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002425 */
2426xmlIDPtr
2427xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2428 xmlAttrPtr attr) {
2429 xmlIDPtr ret;
2430 xmlIDTablePtr table;
2431
2432 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002433 return(NULL);
2434 }
2435 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002436 return(NULL);
2437 }
2438 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002439 return(NULL);
2440 }
2441
2442 /*
2443 * Create the ID table if needed.
2444 */
2445 table = (xmlIDTablePtr) doc->ids;
2446 if (table == NULL)
2447 doc->ids = table = xmlCreateIDTable();
2448 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002449 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002450 "xmlAddID: Table creation failed!\n");
2451 return(NULL);
2452 }
2453
2454 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2455 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002456 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002457 return(NULL);
2458 }
2459
2460 /*
2461 * fill the structure.
2462 */
2463 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002464 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002465 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2466 /*
2467 * Operating in streaming mode, attr is gonna disapear
2468 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002469 if (doc->dict != NULL)
2470 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2471 else
2472 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002473 ret->attr = NULL;
2474 } else {
2475 ret->attr = attr;
2476 ret->name = NULL;
2477 }
2478 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002479
2480 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002481#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002482 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002483 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002484 */
Daniel Veillardd3669b22004-02-25 12:34:55 +00002485 if ((ctxt != NULL) && (ctxt->error != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002486 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2487 "ID %s already defined\n",
2488 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002489 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002490#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002491 xmlFreeID(ret);
2492 return(NULL);
2493 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002494 if (attr != NULL)
2495 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002496 return(ret);
2497}
2498
2499/**
2500 * xmlFreeIDTable:
2501 * @table: An id table
2502 *
2503 * Deallocate the memory used by an ID hash table.
2504 */
2505void
2506xmlFreeIDTable(xmlIDTablePtr table) {
2507 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2508}
2509
2510/**
2511 * xmlIsID:
2512 * @doc: the document
2513 * @elem: the element carrying the attribute
2514 * @attr: the attribute
2515 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002516 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002517 * then this is done if DTD loading has been requested. In the case
2518 * of HTML documents parsed with the HTML parser, then ID detection is
2519 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002520 *
2521 * Returns 0 or 1 depending on the lookup result
2522 */
2523int
2524xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2525 if (doc == NULL) return(0);
2526 if (attr == NULL) return(0);
2527 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2528 return(0);
2529 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard9ba8e382003-10-28 21:31:45 +00002530 if (((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2531 (xmlStrEqual(BAD_CAST "name", attr->name))) &&
2532 ((elem != NULL) && (!xmlStrEqual(elem->name, BAD_CAST "input"))))
Owen Taylor3473f882001-02-23 17:55:21 +00002533 return(1);
2534 return(0);
2535 } else {
2536 xmlAttributePtr attrDecl;
2537
2538 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002539 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002540 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002541 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002542
2543 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002544 if (fullname == NULL)
2545 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002546 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2547 attr->name);
2548 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2549 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2550 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002551 if ((fullname != fn) && (fullname != elem->name))
2552 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002553 } else {
2554 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2555 attr->name);
2556 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2557 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2558 attr->name);
2559 }
Owen Taylor3473f882001-02-23 17:55:21 +00002560
2561 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2562 return(1);
2563 }
2564 return(0);
2565}
2566
2567/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002568 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002569 * @doc: the document
2570 * @attr: the attribute
2571 *
2572 * Remove the given attribute from the ID table maintained internally.
2573 *
2574 * Returns -1 if the lookup failed and 0 otherwise
2575 */
2576int
2577xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002578 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002579 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002580 xmlChar *ID;
2581
2582 if (doc == NULL) return(-1);
2583 if (attr == NULL) return(-1);
2584 table = (xmlIDTablePtr) doc->ids;
2585 if (table == NULL)
2586 return(-1);
2587
2588 if (attr == NULL)
2589 return(-1);
2590 ID = xmlNodeListGetString(doc, attr->children, 1);
2591 if (ID == NULL)
2592 return(-1);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002593 id = xmlHashLookup(table, ID);
2594 if (id == NULL || id->attr != attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002595 xmlFree(ID);
2596 return(-1);
2597 }
2598 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
2599 xmlFree(ID);
2600 return(0);
2601}
2602
2603/**
2604 * xmlGetID:
2605 * @doc: pointer to the document
2606 * @ID: the ID value
2607 *
2608 * Search the attribute declaring the given ID
2609 *
2610 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2611 */
2612xmlAttrPtr
2613xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2614 xmlIDTablePtr table;
2615 xmlIDPtr id;
2616
2617 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002618 return(NULL);
2619 }
2620
2621 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002622 return(NULL);
2623 }
2624
2625 table = (xmlIDTablePtr) doc->ids;
2626 if (table == NULL)
2627 return(NULL);
2628
2629 id = xmlHashLookup(table, ID);
2630 if (id == NULL)
2631 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002632 if (id->attr == NULL) {
2633 /*
2634 * We are operating on a stream, return a well known reference
2635 * since the attribute node doesn't exist anymore
2636 */
2637 return((xmlAttrPtr) doc);
2638 }
Owen Taylor3473f882001-02-23 17:55:21 +00002639 return(id->attr);
2640}
2641
2642/************************************************************************
2643 * *
2644 * Refs *
2645 * *
2646 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002647typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002648{
2649 xmlListPtr l;
2650 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002651} xmlRemoveMemo;
2652
2653typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2654
2655typedef struct xmlValidateMemo_t
2656{
2657 xmlValidCtxtPtr ctxt;
2658 const xmlChar *name;
2659} xmlValidateMemo;
2660
2661typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002662
2663/**
2664 * xmlCreateRefTable:
2665 *
2666 * create and initialize an empty ref hash table.
2667 *
2668 * Returns the xmlRefTablePtr just created or NULL in case
2669 * of error.
2670 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002671static xmlRefTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002672xmlCreateRefTable(void) {
2673 return(xmlHashCreate(0));
2674}
2675
2676/**
2677 * xmlFreeRef:
2678 * @lk: A list link
2679 *
2680 * Deallocate the memory used by a ref definition
2681 */
2682static void
2683xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002684 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2685 if (ref == NULL) return;
2686 if (ref->value != NULL)
2687 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002688 if (ref->name != NULL)
2689 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002690 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002691}
2692
2693/**
2694 * xmlFreeRefList:
2695 * @list_ref: A list of references.
2696 *
2697 * Deallocate the memory used by a list of references
2698 */
2699static void
2700xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002701 if (list_ref == NULL) return;
2702 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002703}
2704
2705/**
2706 * xmlWalkRemoveRef:
2707 * @data: Contents of current link
2708 * @user: Value supplied by the user
2709 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002710 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002711 */
2712static int
2713xmlWalkRemoveRef(const void *data, const void *user)
2714{
Daniel Veillard37721922001-05-04 15:21:12 +00002715 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2716 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2717 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002718
Daniel Veillard37721922001-05-04 15:21:12 +00002719 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2720 xmlListRemoveFirst(ref_list, (void *)data);
2721 return 0;
2722 }
2723 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002724}
2725
2726/**
Daniel Veillard770075b2004-02-25 10:44:30 +00002727 * xmlDummyCompare
2728 * @data0: Value supplied by the user
2729 * @data1: Value supplied by the user
2730 *
2731 * Do nothing, return 0. Used to create unordered lists.
2732 */
2733static int
Daniel Veillardf54cd532004-02-25 11:52:31 +00002734xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2735 const void *data1 ATTRIBUTE_UNUSED)
Daniel Veillard770075b2004-02-25 10:44:30 +00002736{
2737 return (0);
2738}
2739
2740/**
Owen Taylor3473f882001-02-23 17:55:21 +00002741 * xmlAddRef:
2742 * @ctxt: the validation context
2743 * @doc: pointer to the document
2744 * @value: the value name
2745 * @attr: the attribute holding the Ref
2746 *
2747 * Register a new ref declaration
2748 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002749 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002750 */
2751xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002752xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002753 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002754 xmlRefPtr ret;
2755 xmlRefTablePtr table;
2756 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002757
Daniel Veillard37721922001-05-04 15:21:12 +00002758 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002759 return(NULL);
2760 }
2761 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002762 return(NULL);
2763 }
2764 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002765 return(NULL);
2766 }
Owen Taylor3473f882001-02-23 17:55:21 +00002767
Daniel Veillard37721922001-05-04 15:21:12 +00002768 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002769 * Create the Ref table if needed.
2770 */
Daniel Veillard37721922001-05-04 15:21:12 +00002771 table = (xmlRefTablePtr) doc->refs;
2772 if (table == NULL)
2773 doc->refs = table = xmlCreateRefTable();
2774 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002775 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002776 "xmlAddRef: Table creation failed!\n");
2777 return(NULL);
2778 }
Owen Taylor3473f882001-02-23 17:55:21 +00002779
Daniel Veillard37721922001-05-04 15:21:12 +00002780 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2781 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002782 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002783 return(NULL);
2784 }
Owen Taylor3473f882001-02-23 17:55:21 +00002785
Daniel Veillard37721922001-05-04 15:21:12 +00002786 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002787 * fill the structure.
2788 */
Daniel Veillard37721922001-05-04 15:21:12 +00002789 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002790 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2791 /*
2792 * Operating in streaming mode, attr is gonna disapear
2793 */
2794 ret->name = xmlStrdup(attr->name);
2795 ret->attr = NULL;
2796 } else {
2797 ret->name = NULL;
2798 ret->attr = attr;
2799 }
2800 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002801
Daniel Veillard37721922001-05-04 15:21:12 +00002802 /* To add a reference :-
2803 * References are maintained as a list of references,
2804 * Lookup the entry, if no entry create new nodelist
2805 * Add the owning node to the NodeList
2806 * Return the ref
2807 */
Owen Taylor3473f882001-02-23 17:55:21 +00002808
Daniel Veillard37721922001-05-04 15:21:12 +00002809 if (NULL == (ref_list = xmlHashLookup(table, value))) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002810 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002811 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2812 "xmlAddRef: Reference list creation failed!\n",
2813 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002814 return(NULL);
2815 }
2816 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2817 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002818 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2819 "xmlAddRef: Reference list insertion failed!\n",
2820 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002821 return(NULL);
2822 }
2823 }
Daniel Veillard965983a2004-02-17 16:30:24 +00002824/* xmlListInsert(ref_list, ret); */
2825 xmlListAppend(ref_list, ret);
Daniel Veillard37721922001-05-04 15:21:12 +00002826 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002827}
2828
2829/**
2830 * xmlFreeRefTable:
2831 * @table: An ref table
2832 *
2833 * Deallocate the memory used by an Ref hash table.
2834 */
2835void
2836xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002837 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002838}
2839
2840/**
2841 * xmlIsRef:
2842 * @doc: the document
2843 * @elem: the element carrying the attribute
2844 * @attr: the attribute
2845 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002846 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00002847 * then this is simple, otherwise we use an heuristic: name Ref (upper
2848 * or lowercase).
2849 *
2850 * Returns 0 or 1 depending on the lookup result
2851 */
2852int
2853xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002854 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2855 return(0);
2856 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2857 /* TODO @@@ */
2858 return(0);
2859 } else {
2860 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00002861
Daniel Veillard37721922001-05-04 15:21:12 +00002862 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2863 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2864 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2865 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002866
Daniel Veillard37721922001-05-04 15:21:12 +00002867 if ((attrDecl != NULL) &&
2868 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2869 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2870 return(1);
2871 }
2872 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002873}
2874
2875/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002876 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00002877 * @doc: the document
2878 * @attr: the attribute
2879 *
2880 * Remove the given attribute from the Ref table maintained internally.
2881 *
2882 * Returns -1 if the lookup failed and 0 otherwise
2883 */
2884int
2885xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002886 xmlListPtr ref_list;
2887 xmlRefTablePtr table;
2888 xmlChar *ID;
2889 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00002890
Daniel Veillard37721922001-05-04 15:21:12 +00002891 if (doc == NULL) return(-1);
2892 if (attr == NULL) return(-1);
2893 table = (xmlRefTablePtr) doc->refs;
2894 if (table == NULL)
2895 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002896
Daniel Veillard37721922001-05-04 15:21:12 +00002897 if (attr == NULL)
2898 return(-1);
2899 ID = xmlNodeListGetString(doc, attr->children, 1);
2900 if (ID == NULL)
2901 return(-1);
2902 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00002903
Daniel Veillard37721922001-05-04 15:21:12 +00002904 if(ref_list == NULL) {
2905 xmlFree(ID);
2906 return (-1);
2907 }
2908 /* At this point, ref_list refers to a list of references which
2909 * have the same key as the supplied attr. Our list of references
2910 * is ordered by reference address and we don't have that information
2911 * here to use when removing. We'll have to walk the list and
2912 * check for a matching attribute, when we find one stop the walk
2913 * and remove the entry.
2914 * The list is ordered by reference, so that means we don't have the
2915 * key. Passing the list and the reference to the walker means we
2916 * will have enough data to be able to remove the entry.
2917 */
2918 target.l = ref_list;
2919 target.ap = attr;
2920
2921 /* Remove the supplied attr from our list */
2922 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00002923
Daniel Veillard37721922001-05-04 15:21:12 +00002924 /*If the list is empty then remove the list entry in the hash */
2925 if (xmlListEmpty(ref_list))
2926 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2927 xmlFreeRefList);
2928 xmlFree(ID);
2929 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002930}
2931
2932/**
2933 * xmlGetRefs:
2934 * @doc: pointer to the document
2935 * @ID: the ID value
2936 *
2937 * Find the set of references for the supplied ID.
2938 *
2939 * Returns NULL if not found, otherwise node set for the ID.
2940 */
2941xmlListPtr
2942xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00002943 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00002944
Daniel Veillard37721922001-05-04 15:21:12 +00002945 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002946 return(NULL);
2947 }
Owen Taylor3473f882001-02-23 17:55:21 +00002948
Daniel Veillard37721922001-05-04 15:21:12 +00002949 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002950 return(NULL);
2951 }
Owen Taylor3473f882001-02-23 17:55:21 +00002952
Daniel Veillard37721922001-05-04 15:21:12 +00002953 table = (xmlRefTablePtr) doc->refs;
2954 if (table == NULL)
2955 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002956
Daniel Veillard37721922001-05-04 15:21:12 +00002957 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00002958}
2959
2960/************************************************************************
2961 * *
2962 * Routines for validity checking *
2963 * *
2964 ************************************************************************/
2965
2966/**
2967 * xmlGetDtdElementDesc:
2968 * @dtd: a pointer to the DtD to search
2969 * @name: the element name
2970 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002971 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002972 *
2973 * returns the xmlElementPtr if found or NULL
2974 */
2975
2976xmlElementPtr
2977xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2978 xmlElementTablePtr table;
2979 xmlElementPtr cur;
2980 xmlChar *uqname = NULL, *prefix = NULL;
2981
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002982 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002983 if (dtd->elements == NULL)
2984 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002985 table = (xmlElementTablePtr) dtd->elements;
2986
2987 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002988 if (uqname != NULL)
2989 name = uqname;
2990 cur = xmlHashLookup2(table, name, prefix);
2991 if (prefix != NULL) xmlFree(prefix);
2992 if (uqname != NULL) xmlFree(uqname);
2993 return(cur);
2994}
2995/**
2996 * xmlGetDtdElementDesc2:
2997 * @dtd: a pointer to the DtD to search
2998 * @name: the element name
2999 * @create: create an empty description if not found
3000 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003001 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00003002 *
3003 * returns the xmlElementPtr if found or NULL
3004 */
3005
Daniel Veillard86fd5a72001-12-13 14:55:21 +00003006static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00003007xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3008 xmlElementTablePtr table;
3009 xmlElementPtr cur;
3010 xmlChar *uqname = NULL, *prefix = NULL;
3011
3012 if (dtd == NULL) return(NULL);
3013 if (dtd->elements == NULL) {
3014 if (!create)
3015 return(NULL);
3016 /*
3017 * Create the Element table if needed.
3018 */
3019 table = (xmlElementTablePtr) dtd->elements;
3020 if (table == NULL) {
3021 table = xmlCreateElementTable();
3022 dtd->elements = (void *) table;
3023 }
3024 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003025 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003026 return(NULL);
3027 }
3028 }
3029 table = (xmlElementTablePtr) dtd->elements;
3030
3031 uqname = xmlSplitQName2(name, &prefix);
3032 if (uqname != NULL)
3033 name = uqname;
3034 cur = xmlHashLookup2(table, name, prefix);
3035 if ((cur == NULL) && (create)) {
3036 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3037 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003038 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003039 return(NULL);
3040 }
3041 memset(cur, 0, sizeof(xmlElement));
3042 cur->type = XML_ELEMENT_DECL;
3043
3044 /*
3045 * fill the structure.
3046 */
3047 cur->name = xmlStrdup(name);
3048 cur->prefix = xmlStrdup(prefix);
3049 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3050
3051 xmlHashAddEntry2(table, name, prefix, cur);
3052 }
3053 if (prefix != NULL) xmlFree(prefix);
3054 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003055 return(cur);
3056}
3057
3058/**
3059 * xmlGetDtdQElementDesc:
3060 * @dtd: a pointer to the DtD to search
3061 * @name: the element name
3062 * @prefix: the element namespace prefix
3063 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003064 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003065 *
3066 * returns the xmlElementPtr if found or NULL
3067 */
3068
Daniel Veillard48da9102001-08-07 01:10:10 +00003069xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003070xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3071 const xmlChar *prefix) {
3072 xmlElementTablePtr table;
3073
3074 if (dtd == NULL) return(NULL);
3075 if (dtd->elements == NULL) return(NULL);
3076 table = (xmlElementTablePtr) dtd->elements;
3077
3078 return(xmlHashLookup2(table, name, prefix));
3079}
3080
3081/**
3082 * xmlGetDtdAttrDesc:
3083 * @dtd: a pointer to the DtD to search
3084 * @elem: the element name
3085 * @name: the attribute name
3086 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003087 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003088 * this element.
3089 *
3090 * returns the xmlAttributePtr if found or NULL
3091 */
3092
3093xmlAttributePtr
3094xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3095 xmlAttributeTablePtr table;
3096 xmlAttributePtr cur;
3097 xmlChar *uqname = NULL, *prefix = NULL;
3098
3099 if (dtd == NULL) return(NULL);
3100 if (dtd->attributes == NULL) return(NULL);
3101
3102 table = (xmlAttributeTablePtr) dtd->attributes;
3103 if (table == NULL)
3104 return(NULL);
3105
3106 uqname = xmlSplitQName2(name, &prefix);
3107
3108 if (uqname != NULL) {
3109 cur = xmlHashLookup3(table, uqname, prefix, elem);
3110 if (prefix != NULL) xmlFree(prefix);
3111 if (uqname != NULL) xmlFree(uqname);
3112 } else
3113 cur = xmlHashLookup3(table, name, NULL, elem);
3114 return(cur);
3115}
3116
3117/**
3118 * xmlGetDtdQAttrDesc:
3119 * @dtd: a pointer to the DtD to search
3120 * @elem: the element name
3121 * @name: the attribute name
3122 * @prefix: the attribute namespace prefix
3123 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003124 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003125 * this element.
3126 *
3127 * returns the xmlAttributePtr if found or NULL
3128 */
3129
Daniel Veillard48da9102001-08-07 01:10:10 +00003130xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003131xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3132 const xmlChar *prefix) {
3133 xmlAttributeTablePtr table;
3134
3135 if (dtd == NULL) return(NULL);
3136 if (dtd->attributes == NULL) return(NULL);
3137 table = (xmlAttributeTablePtr) dtd->attributes;
3138
3139 return(xmlHashLookup3(table, name, prefix, elem));
3140}
3141
3142/**
3143 * xmlGetDtdNotationDesc:
3144 * @dtd: a pointer to the DtD to search
3145 * @name: the notation name
3146 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003147 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003148 *
3149 * returns the xmlNotationPtr if found or NULL
3150 */
3151
3152xmlNotationPtr
3153xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3154 xmlNotationTablePtr table;
3155
3156 if (dtd == NULL) return(NULL);
3157 if (dtd->notations == NULL) return(NULL);
3158 table = (xmlNotationTablePtr) dtd->notations;
3159
3160 return(xmlHashLookup(table, name));
3161}
3162
Daniel Veillardf54cd532004-02-25 11:52:31 +00003163#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003164/**
3165 * xmlValidateNotationUse:
3166 * @ctxt: the validation context
3167 * @doc: the document
3168 * @notationName: the notation name to check
3169 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003170 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003171 * - [ VC: Notation Declared ]
3172 *
3173 * returns 1 if valid or 0 otherwise
3174 */
3175
3176int
3177xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3178 const xmlChar *notationName) {
3179 xmlNotationPtr notaDecl;
3180 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3181
3182 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3183 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3184 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3185
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003186 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003187 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3188 "NOTATION %s is not declared\n",
3189 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003190 return(0);
3191 }
3192 return(1);
3193}
Daniel Veillardf54cd532004-02-25 11:52:31 +00003194#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003195
3196/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003197 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003198 * @doc: the document
3199 * @name: the element name
3200 *
3201 * Search in the DtDs whether an element accept Mixed content (or ANY)
3202 * basically if it is supposed to accept text childs
3203 *
3204 * returns 0 if no, 1 if yes, and -1 if no element description is available
3205 */
3206
3207int
3208xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3209 xmlElementPtr elemDecl;
3210
3211 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3212
3213 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3214 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3215 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3216 if (elemDecl == NULL) return(-1);
3217 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003218 case XML_ELEMENT_TYPE_UNDEFINED:
3219 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003220 case XML_ELEMENT_TYPE_ELEMENT:
3221 return(0);
3222 case XML_ELEMENT_TYPE_EMPTY:
3223 /*
3224 * return 1 for EMPTY since we want VC error to pop up
3225 * on <empty> </empty> for example
3226 */
3227 case XML_ELEMENT_TYPE_ANY:
3228 case XML_ELEMENT_TYPE_MIXED:
3229 return(1);
3230 }
3231 return(1);
3232}
3233
Daniel Veillard4432df22003-09-28 18:58:27 +00003234#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003235/**
3236 * xmlValidateNameValue:
3237 * @value: an Name value
3238 *
3239 * Validate that the given value match Name production
3240 *
3241 * returns 1 if valid or 0 otherwise
3242 */
3243
Daniel Veillard9b731d72002-04-14 12:56:08 +00003244int
Owen Taylor3473f882001-02-23 17:55:21 +00003245xmlValidateNameValue(const xmlChar *value) {
3246 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003247 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003248
3249 if (value == NULL) return(0);
3250 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003251 val = xmlStringCurrentChar(NULL, cur, &len);
3252 cur += len;
3253 if (!IS_LETTER(val) && (val != '_') &&
3254 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003255 return(0);
3256 }
3257
Daniel Veillardd8224e02002-01-13 15:43:22 +00003258 val = xmlStringCurrentChar(NULL, cur, &len);
3259 cur += len;
3260 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3261 (val == '.') || (val == '-') ||
3262 (val == '_') || (val == ':') ||
3263 (IS_COMBINING(val)) ||
3264 (IS_EXTENDER(val))) {
3265 val = xmlStringCurrentChar(NULL, cur, &len);
3266 cur += len;
3267 }
Owen Taylor3473f882001-02-23 17:55:21 +00003268
Daniel Veillardd8224e02002-01-13 15:43:22 +00003269 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003270
3271 return(1);
3272}
3273
3274/**
3275 * xmlValidateNamesValue:
3276 * @value: an Names value
3277 *
3278 * Validate that the given value match Names production
3279 *
3280 * returns 1 if valid or 0 otherwise
3281 */
3282
Daniel Veillard9b731d72002-04-14 12:56:08 +00003283int
Owen Taylor3473f882001-02-23 17:55:21 +00003284xmlValidateNamesValue(const xmlChar *value) {
3285 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003286 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003287
3288 if (value == NULL) return(0);
3289 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003290 val = xmlStringCurrentChar(NULL, cur, &len);
3291 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003292
Daniel Veillardd8224e02002-01-13 15:43:22 +00003293 if (!IS_LETTER(val) && (val != '_') &&
3294 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003295 return(0);
3296 }
3297
Daniel Veillardd8224e02002-01-13 15:43:22 +00003298 val = xmlStringCurrentChar(NULL, cur, &len);
3299 cur += len;
3300 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3301 (val == '.') || (val == '-') ||
3302 (val == '_') || (val == ':') ||
3303 (IS_COMBINING(val)) ||
3304 (IS_EXTENDER(val))) {
3305 val = xmlStringCurrentChar(NULL, cur, &len);
3306 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003307 }
3308
Daniel Veillard807b4de2004-09-26 14:42:56 +00003309 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3310 while (val == 0x20) {
3311 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003312 val = xmlStringCurrentChar(NULL, cur, &len);
3313 cur += len;
3314 }
3315
3316 if (!IS_LETTER(val) && (val != '_') &&
3317 (val != ':')) {
3318 return(0);
3319 }
3320 val = xmlStringCurrentChar(NULL, cur, &len);
3321 cur += len;
3322
3323 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3324 (val == '.') || (val == '-') ||
3325 (val == '_') || (val == ':') ||
3326 (IS_COMBINING(val)) ||
3327 (IS_EXTENDER(val))) {
3328 val = xmlStringCurrentChar(NULL, cur, &len);
3329 cur += len;
3330 }
3331 }
3332
3333 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003334
3335 return(1);
3336}
3337
3338/**
3339 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003340 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003341 *
3342 * Validate that the given value match Nmtoken production
3343 *
3344 * [ VC: Name Token ]
3345 *
3346 * returns 1 if valid or 0 otherwise
3347 */
3348
Daniel Veillard9b731d72002-04-14 12:56:08 +00003349int
Owen Taylor3473f882001-02-23 17:55:21 +00003350xmlValidateNmtokenValue(const xmlChar *value) {
3351 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003352 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003353
3354 if (value == NULL) return(0);
3355 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003356 val = xmlStringCurrentChar(NULL, cur, &len);
3357 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003358
Daniel Veillardd8224e02002-01-13 15:43:22 +00003359 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3360 (val != '.') && (val != '-') &&
3361 (val != '_') && (val != ':') &&
3362 (!IS_COMBINING(val)) &&
3363 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003364 return(0);
3365
Daniel Veillardd8224e02002-01-13 15:43:22 +00003366 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3367 (val == '.') || (val == '-') ||
3368 (val == '_') || (val == ':') ||
3369 (IS_COMBINING(val)) ||
3370 (IS_EXTENDER(val))) {
3371 val = xmlStringCurrentChar(NULL, cur, &len);
3372 cur += len;
3373 }
Owen Taylor3473f882001-02-23 17:55:21 +00003374
Daniel Veillardd8224e02002-01-13 15:43:22 +00003375 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003376
3377 return(1);
3378}
3379
3380/**
3381 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003382 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003383 *
3384 * Validate that the given value match Nmtokens production
3385 *
3386 * [ VC: Name Token ]
3387 *
3388 * returns 1 if valid or 0 otherwise
3389 */
3390
Daniel Veillard9b731d72002-04-14 12:56:08 +00003391int
Owen Taylor3473f882001-02-23 17:55:21 +00003392xmlValidateNmtokensValue(const xmlChar *value) {
3393 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003394 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003395
3396 if (value == NULL) return(0);
3397 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003398 val = xmlStringCurrentChar(NULL, cur, &len);
3399 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003400
Daniel Veillardd8224e02002-01-13 15:43:22 +00003401 while (IS_BLANK(val)) {
3402 val = xmlStringCurrentChar(NULL, cur, &len);
3403 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003404 }
3405
Daniel Veillardd8224e02002-01-13 15:43:22 +00003406 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3407 (val != '.') && (val != '-') &&
3408 (val != '_') && (val != ':') &&
3409 (!IS_COMBINING(val)) &&
3410 (!IS_EXTENDER(val)))
3411 return(0);
3412
3413 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3414 (val == '.') || (val == '-') ||
3415 (val == '_') || (val == ':') ||
3416 (IS_COMBINING(val)) ||
3417 (IS_EXTENDER(val))) {
3418 val = xmlStringCurrentChar(NULL, cur, &len);
3419 cur += len;
3420 }
3421
Daniel Veillard807b4de2004-09-26 14:42:56 +00003422 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3423 while (val == 0x20) {
3424 while (val == 0x20) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003425 val = xmlStringCurrentChar(NULL, cur, &len);
3426 cur += len;
3427 }
3428 if (val == 0) return(1);
3429
3430 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3431 (val != '.') && (val != '-') &&
3432 (val != '_') && (val != ':') &&
3433 (!IS_COMBINING(val)) &&
3434 (!IS_EXTENDER(val)))
3435 return(0);
3436
3437 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3438 (val == '.') || (val == '-') ||
3439 (val == '_') || (val == ':') ||
3440 (IS_COMBINING(val)) ||
3441 (IS_EXTENDER(val))) {
3442 val = xmlStringCurrentChar(NULL, cur, &len);
3443 cur += len;
3444 }
3445 }
3446
3447 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003448
3449 return(1);
3450}
3451
3452/**
3453 * xmlValidateNotationDecl:
3454 * @ctxt: the validation context
3455 * @doc: a document instance
3456 * @nota: a notation definition
3457 *
3458 * Try to validate a single notation definition
3459 * basically it does the following checks as described by the
3460 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003461 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003462 * But this function get called anyway ...
3463 *
3464 * returns 1 if valid or 0 otherwise
3465 */
3466
3467int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003468xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3469 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003470 int ret = 1;
3471
3472 return(ret);
3473}
3474
3475/**
3476 * xmlValidateAttributeValue:
3477 * @type: an attribute type
3478 * @value: an attribute value
3479 *
3480 * Validate that the given attribute value match the proper production
3481 *
3482 * [ VC: ID ]
3483 * Values of type ID must match the Name production....
3484 *
3485 * [ VC: IDREF ]
3486 * Values of type IDREF must match the Name production, and values
3487 * of type IDREFS must match Names ...
3488 *
3489 * [ VC: Entity Name ]
3490 * Values of type ENTITY must match the Name production, values
3491 * of type ENTITIES must match Names ...
3492 *
3493 * [ VC: Name Token ]
3494 * Values of type NMTOKEN must match the Nmtoken production; values
3495 * of type NMTOKENS must match Nmtokens.
3496 *
3497 * returns 1 if valid or 0 otherwise
3498 */
3499
3500int
3501xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3502 switch (type) {
3503 case XML_ATTRIBUTE_ENTITIES:
3504 case XML_ATTRIBUTE_IDREFS:
3505 return(xmlValidateNamesValue(value));
3506 case XML_ATTRIBUTE_ENTITY:
3507 case XML_ATTRIBUTE_IDREF:
3508 case XML_ATTRIBUTE_ID:
3509 case XML_ATTRIBUTE_NOTATION:
3510 return(xmlValidateNameValue(value));
3511 case XML_ATTRIBUTE_NMTOKENS:
3512 case XML_ATTRIBUTE_ENUMERATION:
3513 return(xmlValidateNmtokensValue(value));
3514 case XML_ATTRIBUTE_NMTOKEN:
3515 return(xmlValidateNmtokenValue(value));
3516 case XML_ATTRIBUTE_CDATA:
3517 break;
3518 }
3519 return(1);
3520}
3521
3522/**
3523 * xmlValidateAttributeValue2:
3524 * @ctxt: the validation context
3525 * @doc: the document
3526 * @name: the attribute name (used for error reporting only)
3527 * @type: the attribute type
3528 * @value: the attribute value
3529 *
3530 * Validate that the given attribute value match a given type.
3531 * This typically cannot be done before having finished parsing
3532 * the subsets.
3533 *
3534 * [ VC: IDREF ]
3535 * Values of type IDREF must match one of the declared IDs
3536 * Values of type IDREFS must match a sequence of the declared IDs
3537 * each Name must match the value of an ID attribute on some element
3538 * in the XML document; i.e. IDREF values must match the value of
3539 * some ID attribute
3540 *
3541 * [ VC: Entity Name ]
3542 * Values of type ENTITY must match one declared entity
3543 * Values of type ENTITIES must match a sequence of declared entities
3544 *
3545 * [ VC: Notation Attributes ]
3546 * all notation names in the declaration must be declared.
3547 *
3548 * returns 1 if valid or 0 otherwise
3549 */
3550
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003551static int
Owen Taylor3473f882001-02-23 17:55:21 +00003552xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3553 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3554 int ret = 1;
3555 switch (type) {
3556 case XML_ATTRIBUTE_IDREFS:
3557 case XML_ATTRIBUTE_IDREF:
3558 case XML_ATTRIBUTE_ID:
3559 case XML_ATTRIBUTE_NMTOKENS:
3560 case XML_ATTRIBUTE_ENUMERATION:
3561 case XML_ATTRIBUTE_NMTOKEN:
3562 case XML_ATTRIBUTE_CDATA:
3563 break;
3564 case XML_ATTRIBUTE_ENTITY: {
3565 xmlEntityPtr ent;
3566
3567 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003568 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003569 if ((ent == NULL) && (doc->standalone == 1)) {
3570 doc->standalone = 0;
3571 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003572 }
Owen Taylor3473f882001-02-23 17:55:21 +00003573 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003574 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3575 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003576 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003577 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003578 ret = 0;
3579 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003580 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3581 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003582 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003583 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003584 ret = 0;
3585 }
3586 break;
3587 }
3588 case XML_ATTRIBUTE_ENTITIES: {
3589 xmlChar *dup, *nam = NULL, *cur, save;
3590 xmlEntityPtr ent;
3591
3592 dup = xmlStrdup(value);
3593 if (dup == NULL)
3594 return(0);
3595 cur = dup;
3596 while (*cur != 0) {
3597 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003598 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003599 save = *cur;
3600 *cur = 0;
3601 ent = xmlGetDocEntity(doc, nam);
3602 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003603 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3604 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003605 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003606 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003607 ret = 0;
3608 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003609 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3610 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003611 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003612 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003613 ret = 0;
3614 }
3615 if (save == 0)
3616 break;
3617 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003618 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003619 }
3620 xmlFree(dup);
3621 break;
3622 }
3623 case XML_ATTRIBUTE_NOTATION: {
3624 xmlNotationPtr nota;
3625
3626 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3627 if ((nota == NULL) && (doc->extSubset != NULL))
3628 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3629
3630 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003631 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3632 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003633 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003634 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003635 ret = 0;
3636 }
3637 break;
3638 }
3639 }
3640 return(ret);
3641}
3642
3643/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003644 * xmlValidCtxtNormalizeAttributeValue:
3645 * @ctxt: the validation context
3646 * @doc: the document
3647 * @elem: the parent
3648 * @name: the attribute name
3649 * @value: the attribute value
3650 * @ctxt: the validation context or NULL
3651 *
3652 * Does the validation related extra step of the normalization of attribute
3653 * values:
3654 *
3655 * If the declared value is not CDATA, then the XML processor must further
3656 * process the normalized attribute value by discarding any leading and
3657 * trailing space (#x20) characters, and by replacing sequences of space
3658 * (#x20) characters by single space (#x20) character.
3659 *
3660 * Also check VC: Standalone Document Declaration in P32, and update
3661 * ctxt->valid accordingly
3662 *
3663 * returns a new normalized string if normalization is needed, NULL otherwise
3664 * the caller must free the returned value.
3665 */
3666
3667xmlChar *
3668xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3669 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3670 xmlChar *ret, *dst;
3671 const xmlChar *src;
3672 xmlAttributePtr attrDecl = NULL;
3673 int extsubset = 0;
3674
3675 if (doc == NULL) return(NULL);
3676 if (elem == NULL) return(NULL);
3677 if (name == NULL) return(NULL);
3678 if (value == NULL) return(NULL);
3679
3680 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003681 xmlChar fn[50];
3682 xmlChar *fullname;
3683
3684 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3685 if (fullname == NULL)
3686 return(0);
3687 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003688 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003689 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003690 if (attrDecl != NULL)
3691 extsubset = 1;
3692 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003693 if ((fullname != fn) && (fullname != elem->name))
3694 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003695 }
3696 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3697 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3698 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3699 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3700 if (attrDecl != NULL)
3701 extsubset = 1;
3702 }
3703
3704 if (attrDecl == NULL)
3705 return(NULL);
3706 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3707 return(NULL);
3708
3709 ret = xmlStrdup(value);
3710 if (ret == NULL)
3711 return(NULL);
3712 src = value;
3713 dst = ret;
3714 while (*src == 0x20) src++;
3715 while (*src != 0) {
3716 if (*src == 0x20) {
3717 while (*src == 0x20) src++;
3718 if (*src != 0)
3719 *dst++ = 0x20;
3720 } else {
3721 *dst++ = *src++;
3722 }
3723 }
3724 *dst = 0;
3725 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003726 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003727"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003728 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003729 ctxt->valid = 0;
3730 }
3731 return(ret);
3732}
3733
3734/**
Owen Taylor3473f882001-02-23 17:55:21 +00003735 * xmlValidNormalizeAttributeValue:
3736 * @doc: the document
3737 * @elem: the parent
3738 * @name: the attribute name
3739 * @value: the attribute value
3740 *
3741 * Does the validation related extra step of the normalization of attribute
3742 * values:
3743 *
3744 * If the declared value is not CDATA, then the XML processor must further
3745 * process the normalized attribute value by discarding any leading and
3746 * trailing space (#x20) characters, and by replacing sequences of space
3747 * (#x20) characters by single space (#x20) character.
3748 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003749 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003750 * the caller must free the returned value.
3751 */
3752
3753xmlChar *
3754xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3755 const xmlChar *name, const xmlChar *value) {
3756 xmlChar *ret, *dst;
3757 const xmlChar *src;
3758 xmlAttributePtr attrDecl = NULL;
3759
3760 if (doc == NULL) return(NULL);
3761 if (elem == NULL) return(NULL);
3762 if (name == NULL) return(NULL);
3763 if (value == NULL) return(NULL);
3764
3765 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003766 xmlChar fn[50];
3767 xmlChar *fullname;
3768
3769 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3770 if (fullname == NULL)
3771 return(0);
3772 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003773 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003774 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3775 if ((fullname != fn) && (fullname != elem->name))
3776 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003777 }
3778 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3779 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3780 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3781
3782 if (attrDecl == NULL)
3783 return(NULL);
3784 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3785 return(NULL);
3786
3787 ret = xmlStrdup(value);
3788 if (ret == NULL)
3789 return(NULL);
3790 src = value;
3791 dst = ret;
3792 while (*src == 0x20) src++;
3793 while (*src != 0) {
3794 if (*src == 0x20) {
3795 while (*src == 0x20) src++;
3796 if (*src != 0)
3797 *dst++ = 0x20;
3798 } else {
3799 *dst++ = *src++;
3800 }
3801 }
3802 *dst = 0;
3803 return(ret);
3804}
3805
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003806static void
Owen Taylor3473f882001-02-23 17:55:21 +00003807xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003808 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003809 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3810}
3811
3812/**
3813 * xmlValidateAttributeDecl:
3814 * @ctxt: the validation context
3815 * @doc: a document instance
3816 * @attr: an attribute definition
3817 *
3818 * Try to validate a single attribute definition
3819 * basically it does the following checks as described by the
3820 * XML-1.0 recommendation:
3821 * - [ VC: Attribute Default Legal ]
3822 * - [ VC: Enumeration ]
3823 * - [ VC: ID Attribute Default ]
3824 *
3825 * The ID/IDREF uniqueness and matching are done separately
3826 *
3827 * returns 1 if valid or 0 otherwise
3828 */
3829
3830int
3831xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3832 xmlAttributePtr attr) {
3833 int ret = 1;
3834 int val;
3835 CHECK_DTD;
3836 if(attr == NULL) return(1);
3837
3838 /* Attribute Default Legal */
3839 /* Enumeration */
3840 if (attr->defaultValue != NULL) {
3841 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3842 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003843 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003844 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003845 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003846 }
3847 ret &= val;
3848 }
3849
3850 /* ID Attribute Default */
3851 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3852 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3853 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003854 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003855 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003856 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003857 ret = 0;
3858 }
3859
3860 /* One ID per Element Type */
3861 if (attr->atype == XML_ATTRIBUTE_ID) {
3862 int nbId;
3863
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003864 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00003865 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3866 attr->elem);
3867 if (elem != NULL) {
3868 nbId = xmlScanIDAttributeDecl(NULL, elem);
3869 } else {
3870 xmlAttributeTablePtr table;
3871
3872 /*
3873 * The attribute may be declared in the internal subset and the
3874 * element in the external subset.
3875 */
3876 nbId = 0;
3877 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3878 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3879 xmlValidateAttributeIdCallback, &nbId);
3880 }
3881 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003882
3883 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003884 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3885 attr->elem, nbId, attr->name);
3886 } else if (doc->extSubset != NULL) {
3887 int extId = 0;
3888 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3889 if (elem != NULL) {
3890 extId = xmlScanIDAttributeDecl(NULL, elem);
3891 }
3892 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003893 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003894 "Element %s has %d ID attribute defined in the external subset : %s\n",
3895 attr->elem, extId, attr->name);
3896 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003897 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003898"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003899 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003900 }
3901 }
3902 }
3903
3904 /* Validity Constraint: Enumeration */
3905 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3906 xmlEnumerationPtr tree = attr->tree;
3907 while (tree != NULL) {
3908 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3909 tree = tree->next;
3910 }
3911 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003912 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003913"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003914 attr->defaultValue, attr->name, attr->elem);
3915 ret = 0;
3916 }
3917 }
3918
3919 return(ret);
3920}
3921
3922/**
3923 * xmlValidateElementDecl:
3924 * @ctxt: the validation context
3925 * @doc: a document instance
3926 * @elem: an element definition
3927 *
3928 * Try to validate a single element definition
3929 * basically it does the following checks as described by the
3930 * XML-1.0 recommendation:
3931 * - [ VC: One ID per Element Type ]
3932 * - [ VC: No Duplicate Types ]
3933 * - [ VC: Unique Element Type Declaration ]
3934 *
3935 * returns 1 if valid or 0 otherwise
3936 */
3937
3938int
3939xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3940 xmlElementPtr elem) {
3941 int ret = 1;
3942 xmlElementPtr tst;
3943
3944 CHECK_DTD;
3945
3946 if (elem == NULL) return(1);
3947
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003948#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00003949#ifdef LIBXML_REGEXP_ENABLED
3950 /* Build the regexp associated to the content model */
3951 ret = xmlValidBuildContentModel(ctxt, elem);
3952#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003953#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00003954
Owen Taylor3473f882001-02-23 17:55:21 +00003955 /* No Duplicate Types */
3956 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3957 xmlElementContentPtr cur, next;
3958 const xmlChar *name;
3959
3960 cur = elem->content;
3961 while (cur != NULL) {
3962 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3963 if (cur->c1 == NULL) break;
3964 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3965 name = cur->c1->name;
3966 next = cur->c2;
3967 while (next != NULL) {
3968 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00003969 if ((xmlStrEqual(next->name, name)) &&
3970 (xmlStrEqual(next->prefix, cur->prefix))) {
3971 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003972 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00003973 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003974 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003975 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003976 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003977 "Definition of %s has duplicate references of %s:%s\n",
3978 elem->name, cur->prefix, name);
3979 }
Owen Taylor3473f882001-02-23 17:55:21 +00003980 ret = 0;
3981 }
3982 break;
3983 }
3984 if (next->c1 == NULL) break;
3985 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00003986 if ((xmlStrEqual(next->c1->name, name)) &&
3987 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
3988 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003989 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003990 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003991 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003992 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003993 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003994 "Definition of %s has duplicate references to %s:%s\n",
3995 elem->name, cur->prefix, name);
3996 }
Owen Taylor3473f882001-02-23 17:55:21 +00003997 ret = 0;
3998 }
3999 next = next->c2;
4000 }
4001 }
4002 cur = cur->c2;
4003 }
4004 }
4005
4006 /* VC: Unique Element Type Declaration */
4007 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004008 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004009 ((tst->prefix == elem->prefix) ||
4010 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004011 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004012 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4013 "Redefinition of element %s\n",
4014 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004015 ret = 0;
4016 }
4017 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004018 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004019 ((tst->prefix == elem->prefix) ||
4020 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004021 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004022 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4023 "Redefinition of element %s\n",
4024 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004025 ret = 0;
4026 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004027 /* One ID per Element Type
4028 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004029 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4030 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004031 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004032 return(ret);
4033}
4034
4035/**
4036 * xmlValidateOneAttribute:
4037 * @ctxt: the validation context
4038 * @doc: a document instance
4039 * @elem: an element instance
4040 * @attr: an attribute instance
4041 * @value: the attribute value (without entities processing)
4042 *
4043 * Try to validate a single attribute for an element
4044 * basically it does the following checks as described by the
4045 * XML-1.0 recommendation:
4046 * - [ VC: Attribute Value Type ]
4047 * - [ VC: Fixed Attribute Default ]
4048 * - [ VC: Entity Name ]
4049 * - [ VC: Name Token ]
4050 * - [ VC: ID ]
4051 * - [ VC: IDREF ]
4052 * - [ VC: Entity Name ]
4053 * - [ VC: Notation Attributes ]
4054 *
4055 * The ID/IDREF uniqueness and matching are done separately
4056 *
4057 * returns 1 if valid or 0 otherwise
4058 */
4059
4060int
4061xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004062 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4063{
Owen Taylor3473f882001-02-23 17:55:21 +00004064 xmlAttributePtr attrDecl = NULL;
4065 int val;
4066 int ret = 1;
4067
4068 CHECK_DTD;
4069 if ((elem == NULL) || (elem->name == NULL)) return(0);
4070 if ((attr == NULL) || (attr->name == NULL)) return(0);
4071
4072 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004073 xmlChar fn[50];
4074 xmlChar *fullname;
4075
4076 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4077 if (fullname == NULL)
4078 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004079 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004080 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004081 attr->name, attr->ns->prefix);
4082 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004083 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004084 attr->name, attr->ns->prefix);
4085 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004086 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004087 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4088 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004089 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004090 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004091 if ((fullname != fn) && (fullname != elem->name))
4092 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004093 }
4094 if (attrDecl == NULL) {
4095 if (attr->ns != NULL) {
4096 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4097 attr->name, attr->ns->prefix);
4098 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4099 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4100 attr->name, attr->ns->prefix);
4101 } else {
4102 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4103 elem->name, attr->name);
4104 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4105 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4106 elem->name, attr->name);
4107 }
4108 }
4109
4110
4111 /* Validity Constraint: Attribute Value Type */
4112 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004113 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004114 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004115 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004116 return(0);
4117 }
4118 attr->atype = attrDecl->atype;
4119
4120 val = xmlValidateAttributeValue(attrDecl->atype, value);
4121 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004122 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004123 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004124 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004125 ret = 0;
4126 }
4127
4128 /* Validity constraint: Fixed Attribute Default */
4129 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4130 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004131 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004132 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004133 attr->name, elem->name, attrDecl->defaultValue);
4134 ret = 0;
4135 }
4136 }
4137
4138 /* Validity Constraint: ID uniqueness */
4139 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4140 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4141 ret = 0;
4142 }
4143
4144 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4145 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4146 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4147 ret = 0;
4148 }
4149
4150 /* Validity Constraint: Notation Attributes */
4151 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4152 xmlEnumerationPtr tree = attrDecl->tree;
4153 xmlNotationPtr nota;
4154
4155 /* First check that the given NOTATION was declared */
4156 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4157 if (nota == NULL)
4158 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4159
4160 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004161 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004162 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004163 value, attr->name, elem->name);
4164 ret = 0;
4165 }
4166
4167 /* Second, verify that it's among the list */
4168 while (tree != NULL) {
4169 if (xmlStrEqual(tree->name, value)) break;
4170 tree = tree->next;
4171 }
4172 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004173 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004174"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004175 value, attr->name, elem->name);
4176 ret = 0;
4177 }
4178 }
4179
4180 /* Validity Constraint: Enumeration */
4181 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4182 xmlEnumerationPtr tree = attrDecl->tree;
4183 while (tree != NULL) {
4184 if (xmlStrEqual(tree->name, value)) break;
4185 tree = tree->next;
4186 }
4187 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004188 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004189 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004190 value, attr->name, elem->name);
4191 ret = 0;
4192 }
4193 }
4194
4195 /* Fixed Attribute Default */
4196 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4197 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004198 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004199 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004200 attr->name, elem->name, attrDecl->defaultValue);
4201 ret = 0;
4202 }
4203
4204 /* Extra check for the attribute value */
4205 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4206 attrDecl->atype, value);
4207
4208 return(ret);
4209}
4210
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004211/**
4212 * xmlValidateOneNamespace:
4213 * @ctxt: the validation context
4214 * @doc: a document instance
4215 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004216 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004217 * @ns: an namespace declaration instance
4218 * @value: the attribute value (without entities processing)
4219 *
4220 * Try to validate a single namespace declaration for an element
4221 * basically it does the following checks as described by the
4222 * XML-1.0 recommendation:
4223 * - [ VC: Attribute Value Type ]
4224 * - [ VC: Fixed Attribute Default ]
4225 * - [ VC: Entity Name ]
4226 * - [ VC: Name Token ]
4227 * - [ VC: ID ]
4228 * - [ VC: IDREF ]
4229 * - [ VC: Entity Name ]
4230 * - [ VC: Notation Attributes ]
4231 *
4232 * The ID/IDREF uniqueness and matching are done separately
4233 *
4234 * returns 1 if valid or 0 otherwise
4235 */
4236
4237int
4238xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4239xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4240 /* xmlElementPtr elemDecl; */
4241 xmlAttributePtr attrDecl = NULL;
4242 int val;
4243 int ret = 1;
4244
4245 CHECK_DTD;
4246 if ((elem == NULL) || (elem->name == NULL)) return(0);
4247 if ((ns == NULL) || (ns->href == NULL)) return(0);
4248
4249 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004250 xmlChar fn[50];
4251 xmlChar *fullname;
4252
4253 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4254 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004255 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004256 return(0);
4257 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004258 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004259 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004260 ns->prefix, BAD_CAST "xmlns");
4261 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004262 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004263 ns->prefix, BAD_CAST "xmlns");
4264 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004265 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004266 BAD_CAST "xmlns");
4267 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004268 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004269 BAD_CAST "xmlns");
4270 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004271 if ((fullname != fn) && (fullname != elem->name))
4272 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004273 }
4274 if (attrDecl == NULL) {
4275 if (ns->prefix != NULL) {
4276 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4277 ns->prefix, BAD_CAST "xmlns");
4278 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4279 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4280 ns->prefix, BAD_CAST "xmlns");
4281 } else {
4282 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4283 elem->name, BAD_CAST "xmlns");
4284 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4285 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4286 elem->name, BAD_CAST "xmlns");
4287 }
4288 }
4289
4290
4291 /* Validity Constraint: Attribute Value Type */
4292 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004293 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004294 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004295 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004296 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004297 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004298 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004299 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004300 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004301 }
4302 return(0);
4303 }
4304
4305 val = xmlValidateAttributeValue(attrDecl->atype, value);
4306 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004307 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004308 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004309 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004310 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004311 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004312 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004313 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004314 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004315 }
4316 ret = 0;
4317 }
4318
4319 /* Validity constraint: Fixed Attribute Default */
4320 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4321 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004322 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004323 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004324 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4325 ns->prefix, elem->name, attrDecl->defaultValue);
4326 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004327 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004328 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004329 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004330 }
4331 ret = 0;
4332 }
4333 }
4334
4335 /* Validity Constraint: ID uniqueness */
4336 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4337 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4338 ret = 0;
4339 }
4340
4341 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4342 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4343 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4344 ret = 0;
4345 }
4346
4347 /* Validity Constraint: Notation Attributes */
4348 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4349 xmlEnumerationPtr tree = attrDecl->tree;
4350 xmlNotationPtr nota;
4351
4352 /* First check that the given NOTATION was declared */
4353 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4354 if (nota == NULL)
4355 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4356
4357 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004358 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004359 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004360 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4361 value, ns->prefix, elem->name);
4362 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004363 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004364 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004365 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004366 }
4367 ret = 0;
4368 }
4369
4370 /* Second, verify that it's among the list */
4371 while (tree != NULL) {
4372 if (xmlStrEqual(tree->name, value)) break;
4373 tree = tree->next;
4374 }
4375 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004376 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004377 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004378"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4379 value, ns->prefix, elem->name);
4380 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004381 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004382"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004383 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004384 }
4385 ret = 0;
4386 }
4387 }
4388
4389 /* Validity Constraint: Enumeration */
4390 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4391 xmlEnumerationPtr tree = attrDecl->tree;
4392 while (tree != NULL) {
4393 if (xmlStrEqual(tree->name, value)) break;
4394 tree = tree->next;
4395 }
4396 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004397 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004398 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004399"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4400 value, ns->prefix, elem->name);
4401 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004402 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004403"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004404 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004405 }
4406 ret = 0;
4407 }
4408 }
4409
4410 /* Fixed Attribute Default */
4411 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4412 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004413 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004414 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004415 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4416 ns->prefix, elem->name, attrDecl->defaultValue);
4417 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004418 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004419 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004420 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004421 }
4422 ret = 0;
4423 }
4424
4425 /* Extra check for the attribute value */
4426 if (ns->prefix != NULL) {
4427 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4428 attrDecl->atype, value);
4429 } else {
4430 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4431 attrDecl->atype, value);
4432 }
4433
4434 return(ret);
4435}
4436
Daniel Veillard118aed72002-09-24 14:13:13 +00004437#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004438/**
4439 * xmlValidateSkipIgnorable:
4440 * @ctxt: the validation context
4441 * @child: the child list
4442 *
4443 * Skip ignorable elements w.r.t. the validation process
4444 *
4445 * returns the first element to consider for validation of the content model
4446 */
4447
4448static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004449xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004450 while (child != NULL) {
4451 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004452 /* These things are ignored (skipped) during validation. */
4453 case XML_PI_NODE:
4454 case XML_COMMENT_NODE:
4455 case XML_XINCLUDE_START:
4456 case XML_XINCLUDE_END:
4457 child = child->next;
4458 break;
4459 case XML_TEXT_NODE:
4460 if (xmlIsBlankNode(child))
4461 child = child->next;
4462 else
4463 return(child);
4464 break;
4465 /* keep current node */
4466 default:
4467 return(child);
4468 }
4469 }
4470 return(child);
4471}
4472
4473/**
4474 * xmlValidateElementType:
4475 * @ctxt: the validation context
4476 *
4477 * Try to validate the content model of an element internal function
4478 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004479 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4480 * reference is found and -3 if the validation succeeded but
4481 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004482 */
4483
4484static int
4485xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004486 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004487 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004488
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004489 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004490 if ((NODE == NULL) && (CONT == NULL))
4491 return(1);
4492 if ((NODE == NULL) &&
4493 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4494 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4495 return(1);
4496 }
4497 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004498 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004499 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004500
4501 /*
4502 * We arrive here when more states need to be examined
4503 */
4504cont:
4505
4506 /*
4507 * We just recovered from a rollback generated by a possible
4508 * epsilon transition, go directly to the analysis phase
4509 */
4510 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004511 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004512 DEBUG_VALID_STATE(NODE, CONT)
4513 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004514 goto analyze;
4515 }
4516
4517 DEBUG_VALID_STATE(NODE, CONT)
4518 /*
4519 * we may have to save a backup state here. This is the equivalent
4520 * of handling epsilon transition in NFAs.
4521 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004522 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004523 ((CONT->parent == NULL) ||
4524 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004525 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004526 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004527 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004528 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004529 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4530 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004531 }
4532
4533
4534 /*
4535 * Check first if the content matches
4536 */
4537 switch (CONT->type) {
4538 case XML_ELEMENT_CONTENT_PCDATA:
4539 if (NODE == NULL) {
4540 DEBUG_VALID_MSG("pcdata failed no node");
4541 ret = 0;
4542 break;
4543 }
4544 if (NODE->type == XML_TEXT_NODE) {
4545 DEBUG_VALID_MSG("pcdata found, skip to next");
4546 /*
4547 * go to next element in the content model
4548 * skipping ignorable elems
4549 */
4550 do {
4551 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004552 NODE = xmlValidateSkipIgnorable(NODE);
4553 if ((NODE != NULL) &&
4554 (NODE->type == XML_ENTITY_REF_NODE))
4555 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004556 } while ((NODE != NULL) &&
4557 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004558 (NODE->type != XML_TEXT_NODE) &&
4559 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004560 ret = 1;
4561 break;
4562 } else {
4563 DEBUG_VALID_MSG("pcdata failed");
4564 ret = 0;
4565 break;
4566 }
4567 break;
4568 case XML_ELEMENT_CONTENT_ELEMENT:
4569 if (NODE == NULL) {
4570 DEBUG_VALID_MSG("element failed no node");
4571 ret = 0;
4572 break;
4573 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004574 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4575 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004576 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004577 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4578 ret = (CONT->prefix == NULL);
4579 } else if (CONT->prefix == NULL) {
4580 ret = 0;
4581 } else {
4582 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4583 }
4584 }
4585 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004586 DEBUG_VALID_MSG("element found, skip to next");
4587 /*
4588 * go to next element in the content model
4589 * skipping ignorable elems
4590 */
4591 do {
4592 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004593 NODE = xmlValidateSkipIgnorable(NODE);
4594 if ((NODE != NULL) &&
4595 (NODE->type == XML_ENTITY_REF_NODE))
4596 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004597 } while ((NODE != NULL) &&
4598 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004599 (NODE->type != XML_TEXT_NODE) &&
4600 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004601 } else {
4602 DEBUG_VALID_MSG("element failed");
4603 ret = 0;
4604 break;
4605 }
4606 break;
4607 case XML_ELEMENT_CONTENT_OR:
4608 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004609 * Small optimization.
4610 */
4611 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4612 if ((NODE == NULL) ||
4613 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4614 DEPTH++;
4615 CONT = CONT->c2;
4616 goto cont;
4617 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004618 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4619 ret = (CONT->c1->prefix == NULL);
4620 } else if (CONT->c1->prefix == NULL) {
4621 ret = 0;
4622 } else {
4623 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4624 }
4625 if (ret == 0) {
4626 DEPTH++;
4627 CONT = CONT->c2;
4628 goto cont;
4629 }
Daniel Veillard85349052001-04-20 13:48:21 +00004630 }
4631
4632 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004633 * save the second branch 'or' branch
4634 */
4635 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004636 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4637 OCCURS, ROLLBACK_OR) < 0)
4638 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004639 DEPTH++;
4640 CONT = CONT->c1;
4641 goto cont;
4642 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004643 /*
4644 * Small optimization.
4645 */
4646 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4647 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4648 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4649 if ((NODE == NULL) ||
4650 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4651 DEPTH++;
4652 CONT = CONT->c2;
4653 goto cont;
4654 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004655 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4656 ret = (CONT->c1->prefix == NULL);
4657 } else if (CONT->c1->prefix == NULL) {
4658 ret = 0;
4659 } else {
4660 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4661 }
4662 if (ret == 0) {
4663 DEPTH++;
4664 CONT = CONT->c2;
4665 goto cont;
4666 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004667 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004668 DEPTH++;
4669 CONT = CONT->c1;
4670 goto cont;
4671 }
4672
4673 /*
4674 * At this point handle going up in the tree
4675 */
4676 if (ret == -1) {
4677 DEBUG_VALID_MSG("error found returning");
4678 return(ret);
4679 }
4680analyze:
4681 while (CONT != NULL) {
4682 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004683 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004684 * this level.
4685 */
4686 if (ret == 0) {
4687 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004688 xmlNodePtr cur;
4689
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004690 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004691 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004692 DEBUG_VALID_MSG("Once branch failed, rollback");
4693 if (vstateVPop(ctxt) < 0 ) {
4694 DEBUG_VALID_MSG("exhaustion, failed");
4695 return(0);
4696 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004697 if (cur != ctxt->vstate->node)
4698 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004699 goto cont;
4700 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004701 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004702 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004703 DEBUG_VALID_MSG("Plus branch failed, rollback");
4704 if (vstateVPop(ctxt) < 0 ) {
4705 DEBUG_VALID_MSG("exhaustion, failed");
4706 return(0);
4707 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004708 if (cur != ctxt->vstate->node)
4709 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004710 goto cont;
4711 }
4712 DEBUG_VALID_MSG("Plus branch found");
4713 ret = 1;
4714 break;
4715 case XML_ELEMENT_CONTENT_MULT:
4716#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004717 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004718 DEBUG_VALID_MSG("Mult branch failed");
4719 } else {
4720 DEBUG_VALID_MSG("Mult branch found");
4721 }
4722#endif
4723 ret = 1;
4724 break;
4725 case XML_ELEMENT_CONTENT_OPT:
4726 DEBUG_VALID_MSG("Option branch failed");
4727 ret = 1;
4728 break;
4729 }
4730 } else {
4731 switch (CONT->ocur) {
4732 case XML_ELEMENT_CONTENT_OPT:
4733 DEBUG_VALID_MSG("Option branch succeeded");
4734 ret = 1;
4735 break;
4736 case XML_ELEMENT_CONTENT_ONCE:
4737 DEBUG_VALID_MSG("Once branch succeeded");
4738 ret = 1;
4739 break;
4740 case XML_ELEMENT_CONTENT_PLUS:
4741 if (STATE == ROLLBACK_PARENT) {
4742 DEBUG_VALID_MSG("Plus branch rollback");
4743 ret = 1;
4744 break;
4745 }
4746 if (NODE == NULL) {
4747 DEBUG_VALID_MSG("Plus branch exhausted");
4748 ret = 1;
4749 break;
4750 }
4751 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004752 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004753 goto cont;
4754 case XML_ELEMENT_CONTENT_MULT:
4755 if (STATE == ROLLBACK_PARENT) {
4756 DEBUG_VALID_MSG("Mult branch rollback");
4757 ret = 1;
4758 break;
4759 }
4760 if (NODE == NULL) {
4761 DEBUG_VALID_MSG("Mult branch exhausted");
4762 ret = 1;
4763 break;
4764 }
4765 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004766 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004767 goto cont;
4768 }
4769 }
4770 STATE = 0;
4771
4772 /*
4773 * Then act accordingly at the parent level
4774 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004775 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004776 if (CONT->parent == NULL)
4777 break;
4778
4779 switch (CONT->parent->type) {
4780 case XML_ELEMENT_CONTENT_PCDATA:
4781 DEBUG_VALID_MSG("Error: parent pcdata");
4782 return(-1);
4783 case XML_ELEMENT_CONTENT_ELEMENT:
4784 DEBUG_VALID_MSG("Error: parent element");
4785 return(-1);
4786 case XML_ELEMENT_CONTENT_OR:
4787 if (ret == 1) {
4788 DEBUG_VALID_MSG("Or succeeded");
4789 CONT = CONT->parent;
4790 DEPTH--;
4791 } else {
4792 DEBUG_VALID_MSG("Or failed");
4793 CONT = CONT->parent;
4794 DEPTH--;
4795 }
4796 break;
4797 case XML_ELEMENT_CONTENT_SEQ:
4798 if (ret == 0) {
4799 DEBUG_VALID_MSG("Sequence failed");
4800 CONT = CONT->parent;
4801 DEPTH--;
4802 } else if (CONT == CONT->parent->c1) {
4803 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4804 CONT = CONT->parent->c2;
4805 goto cont;
4806 } else {
4807 DEBUG_VALID_MSG("Sequence succeeded");
4808 CONT = CONT->parent;
4809 DEPTH--;
4810 }
4811 }
4812 }
4813 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004814 xmlNodePtr cur;
4815
4816 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004817 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4818 if (vstateVPop(ctxt) < 0 ) {
4819 DEBUG_VALID_MSG("exhaustion, failed");
4820 return(0);
4821 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004822 if (cur != ctxt->vstate->node)
4823 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004824 goto cont;
4825 }
4826 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004827 xmlNodePtr cur;
4828
4829 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004830 DEBUG_VALID_MSG("Failure, rollback");
4831 if (vstateVPop(ctxt) < 0 ) {
4832 DEBUG_VALID_MSG("exhaustion, failed");
4833 return(0);
4834 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004835 if (cur != ctxt->vstate->node)
4836 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004837 goto cont;
4838 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004839 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004840}
Daniel Veillard23e73572002-09-19 19:56:43 +00004841#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004842
4843/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00004844 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004845 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00004846 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004847 * @content: An element
4848 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4849 *
4850 * This will dump the list of elements to the buffer
4851 * Intended just for the debug routine
4852 */
4853static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00004854xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004855 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00004856 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004857
4858 if (node == NULL) return;
4859 if (glob) strcat(buf, "(");
4860 cur = node;
4861 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004862 len = strlen(buf);
4863 if (size - len < 50) {
4864 if ((size - len > 4) && (buf[len - 1] != '.'))
4865 strcat(buf, " ...");
4866 return;
4867 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004868 switch (cur->type) {
4869 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004870 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004871 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004872 if ((size - len > 4) && (buf[len - 1] != '.'))
4873 strcat(buf, " ...");
4874 return;
4875 }
4876 strcat(buf, (char *) cur->ns->prefix);
4877 strcat(buf, ":");
4878 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004879 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004880 if ((size - len > 4) && (buf[len - 1] != '.'))
4881 strcat(buf, " ...");
4882 return;
4883 }
4884 strcat(buf, (char *) cur->name);
4885 if (cur->next != NULL)
4886 strcat(buf, " ");
4887 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004888 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004889 if (xmlIsBlankNode(cur))
4890 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004891 case XML_CDATA_SECTION_NODE:
4892 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004893 strcat(buf, "CDATA");
4894 if (cur->next != NULL)
4895 strcat(buf, " ");
4896 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004897 case XML_ATTRIBUTE_NODE:
4898 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004899#ifdef LIBXML_DOCB_ENABLED
4900 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004901#endif
4902 case XML_HTML_DOCUMENT_NODE:
4903 case XML_DOCUMENT_TYPE_NODE:
4904 case XML_DOCUMENT_FRAG_NODE:
4905 case XML_NOTATION_NODE:
4906 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004907 strcat(buf, "???");
4908 if (cur->next != NULL)
4909 strcat(buf, " ");
4910 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004911 case XML_ENTITY_NODE:
4912 case XML_PI_NODE:
4913 case XML_DTD_NODE:
4914 case XML_COMMENT_NODE:
4915 case XML_ELEMENT_DECL:
4916 case XML_ATTRIBUTE_DECL:
4917 case XML_ENTITY_DECL:
4918 case XML_XINCLUDE_START:
4919 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004920 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004921 }
4922 cur = cur->next;
4923 }
4924 if (glob) strcat(buf, ")");
4925}
4926
4927/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004928 * xmlValidateElementContent:
4929 * @ctxt: the validation context
4930 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004931 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004932 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004933 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004934 *
4935 * Try to validate the content model of an element
4936 *
4937 * returns 1 if valid or 0 if not and -1 in case of error
4938 */
4939
4940static int
4941xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004942 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004943 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00004944#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00004945 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00004946#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00004947 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004948 xmlElementContentPtr cont;
4949 const xmlChar *name;
4950
4951 if (elemDecl == NULL)
4952 return(-1);
4953 cont = elemDecl->content;
4954 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004955
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004956#ifdef LIBXML_REGEXP_ENABLED
4957 /* Build the regexp associated to the content model */
4958 if (elemDecl->contModel == NULL)
4959 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4960 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004961 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004962 } else {
4963 xmlRegExecCtxtPtr exec;
4964
Daniel Veillardec498e12003-02-05 11:01:50 +00004965 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
4966 return(-1);
4967 }
Daniel Veillard01992e02002-10-09 10:20:30 +00004968 ctxt->nodeMax = 0;
4969 ctxt->nodeNr = 0;
4970 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004971 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4972 if (exec != NULL) {
4973 cur = child;
4974 while (cur != NULL) {
4975 switch (cur->type) {
4976 case XML_ENTITY_REF_NODE:
4977 /*
4978 * Push the current node to be able to roll back
4979 * and process within the entity
4980 */
4981 if ((cur->children != NULL) &&
4982 (cur->children->children != NULL)) {
4983 nodeVPush(ctxt, cur);
4984 cur = cur->children->children;
4985 continue;
4986 }
4987 break;
4988 case XML_TEXT_NODE:
4989 if (xmlIsBlankNode(cur))
4990 break;
4991 ret = 0;
4992 goto fail;
4993 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00004994 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004995 ret = 0;
4996 goto fail;
4997 case XML_ELEMENT_NODE:
4998 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004999 xmlChar fn[50];
5000 xmlChar *fullname;
5001
5002 fullname = xmlBuildQName(cur->name,
5003 cur->ns->prefix, fn, 50);
5004 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005005 ret = -1;
5006 goto fail;
5007 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005008 ret = xmlRegExecPushString(exec, fullname, NULL);
5009 if ((fullname != fn) && (fullname != cur->name))
5010 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005011 } else {
5012 ret = xmlRegExecPushString(exec, cur->name, NULL);
5013 }
5014 break;
5015 default:
5016 break;
5017 }
5018 /*
5019 * Switch to next element
5020 */
5021 cur = cur->next;
5022 while (cur == NULL) {
5023 cur = nodeVPop(ctxt);
5024 if (cur == NULL)
5025 break;
5026 cur = cur->next;
5027 }
5028 }
5029 ret = xmlRegExecPushString(exec, NULL, NULL);
5030fail:
5031 xmlRegFreeExecCtxt(exec);
5032 }
5033 }
5034#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005035 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005036 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005037 */
5038 ctxt->vstateMax = 8;
5039 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5040 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5041 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005042 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005043 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005044 }
5045 /*
5046 * The first entry in the stack is reserved to the current state
5047 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005048 ctxt->nodeMax = 0;
5049 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005050 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005051 ctxt->vstate = &ctxt->vstateTab[0];
5052 ctxt->vstateNr = 1;
5053 CONT = cont;
5054 NODE = child;
5055 DEPTH = 0;
5056 OCCURS = 0;
5057 STATE = 0;
5058 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005059 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005060 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5061 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005062 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005063 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005064 /*
5065 * An entities reference appeared at this level.
5066 * Buid a minimal representation of this node content
5067 * sufficient to run the validation process on it
5068 */
5069 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005070 cur = child;
5071 while (cur != NULL) {
5072 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005073 case XML_ENTITY_REF_NODE:
5074 /*
5075 * Push the current node to be able to roll back
5076 * and process within the entity
5077 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005078 if ((cur->children != NULL) &&
5079 (cur->children->children != NULL)) {
5080 nodeVPush(ctxt, cur);
5081 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005082 continue;
5083 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005084 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005085 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005086 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005087 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005088 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005089 case XML_CDATA_SECTION_NODE:
5090 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005091 case XML_ELEMENT_NODE:
5092 /*
5093 * Allocate a new node and minimally fills in
5094 * what's required
5095 */
5096 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5097 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005098 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005099 xmlFreeNodeList(repl);
5100 ret = -1;
5101 goto done;
5102 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005103 tmp->type = cur->type;
5104 tmp->name = cur->name;
5105 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005106 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005107 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005108 if (repl == NULL)
5109 repl = last = tmp;
5110 else {
5111 last->next = tmp;
5112 last = tmp;
5113 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005114 if (cur->type == XML_CDATA_SECTION_NODE) {
5115 /*
5116 * E59 spaces in CDATA does not match the
5117 * nonterminal S
5118 */
5119 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5120 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005121 break;
5122 default:
5123 break;
5124 }
5125 /*
5126 * Switch to next element
5127 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005128 cur = cur->next;
5129 while (cur == NULL) {
5130 cur = nodeVPop(ctxt);
5131 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005132 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005133 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005134 }
5135 }
5136
5137 /*
5138 * Relaunch the validation
5139 */
5140 ctxt->vstate = &ctxt->vstateTab[0];
5141 ctxt->vstateNr = 1;
5142 CONT = cont;
5143 NODE = repl;
5144 DEPTH = 0;
5145 OCCURS = 0;
5146 STATE = 0;
5147 ret = xmlValidateElementType(ctxt);
5148 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005149#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005150 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005151 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5152 char expr[5000];
5153 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005154
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005155 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005156 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005157 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005158#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005159 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005160 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005161 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005162#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005163 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005164
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005165 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005166 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5167 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5168 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005169 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005170 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5171 "Element content does not follow the DTD, expecting %s, got %s\n",
5172 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005173 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005174 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005175 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005176 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005177 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005178 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005179 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005180 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5181 "Element content does not follow the DTD\n",
5182 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005183 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005184 }
5185 ret = 0;
5186 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005187 if (ret == -3)
5188 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005189
Daniel Veillard23e73572002-09-19 19:56:43 +00005190#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005191done:
5192 /*
5193 * Deallocate the copy if done, and free up the validation stack
5194 */
5195 while (repl != NULL) {
5196 tmp = repl->next;
5197 xmlFree(repl);
5198 repl = tmp;
5199 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005200 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005201 if (ctxt->vstateTab != NULL) {
5202 xmlFree(ctxt->vstateTab);
5203 ctxt->vstateTab = NULL;
5204 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005205#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005206 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005207 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005208 if (ctxt->nodeTab != NULL) {
5209 xmlFree(ctxt->nodeTab);
5210 ctxt->nodeTab = NULL;
5211 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005212 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005213
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005214}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005215
Owen Taylor3473f882001-02-23 17:55:21 +00005216/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005217 * xmlValidateCdataElement:
5218 * @ctxt: the validation context
5219 * @doc: a document instance
5220 * @elem: an element instance
5221 *
5222 * Check that an element follows #CDATA
5223 *
5224 * returns 1 if valid or 0 otherwise
5225 */
5226static int
5227xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5228 xmlNodePtr elem) {
5229 int ret = 1;
5230 xmlNodePtr cur, child;
5231
Daniel Veillardceb09b92002-10-04 11:46:37 +00005232 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005233 return(0);
5234
5235 child = elem->children;
5236
5237 cur = child;
5238 while (cur != NULL) {
5239 switch (cur->type) {
5240 case XML_ENTITY_REF_NODE:
5241 /*
5242 * Push the current node to be able to roll back
5243 * and process within the entity
5244 */
5245 if ((cur->children != NULL) &&
5246 (cur->children->children != NULL)) {
5247 nodeVPush(ctxt, cur);
5248 cur = cur->children->children;
5249 continue;
5250 }
5251 break;
5252 case XML_COMMENT_NODE:
5253 case XML_PI_NODE:
5254 case XML_TEXT_NODE:
5255 case XML_CDATA_SECTION_NODE:
5256 break;
5257 default:
5258 ret = 0;
5259 goto done;
5260 }
5261 /*
5262 * Switch to next element
5263 */
5264 cur = cur->next;
5265 while (cur == NULL) {
5266 cur = nodeVPop(ctxt);
5267 if (cur == NULL)
5268 break;
5269 cur = cur->next;
5270 }
5271 }
5272done:
5273 ctxt->nodeMax = 0;
5274 ctxt->nodeNr = 0;
5275 if (ctxt->nodeTab != NULL) {
5276 xmlFree(ctxt->nodeTab);
5277 ctxt->nodeTab = NULL;
5278 }
5279 return(ret);
5280}
5281
5282/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005283 * xmlValidateCheckMixed:
5284 * @ctxt: the validation context
5285 * @cont: the mixed content model
5286 * @qname: the qualified name as appearing in the serialization
5287 *
5288 * Check if the given node is part of the content model.
5289 *
5290 * Returns 1 if yes, 0 if no, -1 in case of error
5291 */
5292static int
William M. Brackedb65a72004-02-06 07:36:04 +00005293xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005294 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005295 const xmlChar *name;
5296 int plen;
5297 name = xmlSplitQName3(qname, &plen);
5298
5299 if (name == NULL) {
5300 while (cont != NULL) {
5301 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5302 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5303 return(1);
5304 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5305 (cont->c1 != NULL) &&
5306 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5307 if ((cont->c1->prefix == NULL) &&
5308 (xmlStrEqual(cont->c1->name, qname)))
5309 return(1);
5310 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5311 (cont->c1 == NULL) ||
5312 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005313 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5314 "Internal: MIXED struct corrupted\n",
5315 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005316 break;
5317 }
5318 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005319 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005320 } else {
5321 while (cont != NULL) {
5322 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5323 if ((cont->prefix != NULL) &&
5324 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5325 (xmlStrEqual(cont->name, name)))
5326 return(1);
5327 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5328 (cont->c1 != NULL) &&
5329 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5330 if ((cont->c1->prefix != NULL) &&
5331 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5332 (xmlStrEqual(cont->c1->name, name)))
5333 return(1);
5334 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5335 (cont->c1 == NULL) ||
5336 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005337 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5338 "Internal: MIXED struct corrupted\n",
5339 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005340 break;
5341 }
5342 cont = cont->c2;
5343 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005344 }
5345 return(0);
5346}
5347
5348/**
5349 * xmlValidGetElemDecl:
5350 * @ctxt: the validation context
5351 * @doc: a document instance
5352 * @elem: an element instance
5353 * @extsubset: pointer, (out) indicate if the declaration was found
5354 * in the external subset.
5355 *
5356 * Finds a declaration associated to an element in the document.
5357 *
5358 * returns the pointer to the declaration or NULL if not found.
5359 */
5360static xmlElementPtr
5361xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5362 xmlNodePtr elem, int *extsubset) {
5363 xmlElementPtr elemDecl = NULL;
5364 const xmlChar *prefix = NULL;
5365
5366 if ((elem == NULL) || (elem->name == NULL)) return(NULL);
5367 if (extsubset != NULL)
5368 *extsubset = 0;
5369
5370 /*
5371 * Fetch the declaration for the qualified name
5372 */
5373 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5374 prefix = elem->ns->prefix;
5375
5376 if (prefix != NULL) {
5377 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5378 elem->name, prefix);
5379 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5380 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5381 elem->name, prefix);
5382 if ((elemDecl != NULL) && (extsubset != NULL))
5383 *extsubset = 1;
5384 }
5385 }
5386
5387 /*
5388 * Fetch the declaration for the non qualified name
5389 * This is "non-strict" validation should be done on the
5390 * full QName but in that case being flexible makes sense.
5391 */
5392 if (elemDecl == NULL) {
5393 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5394 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5395 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5396 if ((elemDecl != NULL) && (extsubset != NULL))
5397 *extsubset = 1;
5398 }
5399 }
5400 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005401 xmlErrValidNode(ctxt, elem,
5402 XML_DTD_UNKNOWN_ELEM,
5403 "No declaration for element %s\n",
5404 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005405 }
5406 return(elemDecl);
5407}
5408
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005409#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005410/**
5411 * xmlValidatePushElement:
5412 * @ctxt: the validation context
5413 * @doc: a document instance
5414 * @elem: an element instance
5415 * @qname: the qualified name as appearing in the serialization
5416 *
5417 * Push a new element start on the validation stack.
5418 *
5419 * returns 1 if no validation problem was found or 0 otherwise
5420 */
5421int
5422xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5423 xmlNodePtr elem, const xmlChar *qname) {
5424 int ret = 1;
5425 xmlElementPtr eDecl;
5426 int extsubset = 0;
5427
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005428/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005429 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5430 xmlValidStatePtr state = ctxt->vstate;
5431 xmlElementPtr elemDecl;
5432
5433 /*
5434 * Check the new element agaisnt the content model of the new elem.
5435 */
5436 if (state->elemDecl != NULL) {
5437 elemDecl = state->elemDecl;
5438
5439 switch(elemDecl->etype) {
5440 case XML_ELEMENT_TYPE_UNDEFINED:
5441 ret = 0;
5442 break;
5443 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005444 xmlErrValidNode(ctxt, state->node,
5445 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005446 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005447 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005448 ret = 0;
5449 break;
5450 case XML_ELEMENT_TYPE_ANY:
5451 /* I don't think anything is required then */
5452 break;
5453 case XML_ELEMENT_TYPE_MIXED:
5454 /* simple case of declared as #PCDATA */
5455 if ((elemDecl->content != NULL) &&
5456 (elemDecl->content->type ==
5457 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005458 xmlErrValidNode(ctxt, state->node,
5459 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005460 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005461 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005462 ret = 0;
5463 } else {
5464 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5465 qname);
5466 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005467 xmlErrValidNode(ctxt, state->node,
5468 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005469 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005470 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005471 }
5472 }
5473 break;
5474 case XML_ELEMENT_TYPE_ELEMENT:
5475 /*
5476 * TODO:
5477 * VC: Standalone Document Declaration
5478 * - element types with element content, if white space
5479 * occurs directly within any instance of those types.
5480 */
5481 if (state->exec != NULL) {
5482 ret = xmlRegExecPushString(state->exec, qname, NULL);
5483 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005484 xmlErrValidNode(ctxt, state->node,
5485 XML_DTD_CONTENT_MODEL,
5486 "Element %s content does not follow the DTD, Misplaced %s\n",
5487 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005488 ret = 0;
5489 } else {
5490 ret = 1;
5491 }
5492 }
5493 break;
5494 }
5495 }
5496 }
5497 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5498 vstateVPush(ctxt, eDecl, elem);
5499 return(ret);
5500}
5501
5502/**
5503 * xmlValidatePushCData:
5504 * @ctxt: the validation context
5505 * @data: some character data read
5506 * @len: the lenght of the data
5507 *
5508 * check the CData parsed for validation in the current stack
5509 *
5510 * returns 1 if no validation problem was found or 0 otherwise
5511 */
5512int
5513xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5514 int ret = 1;
5515
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005516/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005517 if (len <= 0)
5518 return(ret);
5519 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5520 xmlValidStatePtr state = ctxt->vstate;
5521 xmlElementPtr elemDecl;
5522
5523 /*
5524 * Check the new element agaisnt the content model of the new elem.
5525 */
5526 if (state->elemDecl != NULL) {
5527 elemDecl = state->elemDecl;
5528
5529 switch(elemDecl->etype) {
5530 case XML_ELEMENT_TYPE_UNDEFINED:
5531 ret = 0;
5532 break;
5533 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005534 xmlErrValidNode(ctxt, state->node,
5535 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005536 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005537 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005538 ret = 0;
5539 break;
5540 case XML_ELEMENT_TYPE_ANY:
5541 break;
5542 case XML_ELEMENT_TYPE_MIXED:
5543 break;
5544 case XML_ELEMENT_TYPE_ELEMENT:
5545 if (len > 0) {
5546 int i;
5547
5548 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005549 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005550 xmlErrValidNode(ctxt, state->node,
5551 XML_DTD_CONTENT_MODEL,
5552 "Element %s content does not follow the DTD, Text not allowed\n",
5553 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005554 ret = 0;
5555 goto done;
5556 }
5557 }
5558 /*
5559 * TODO:
5560 * VC: Standalone Document Declaration
5561 * element types with element content, if white space
5562 * occurs directly within any instance of those types.
5563 */
5564 }
5565 break;
5566 }
5567 }
5568 }
5569done:
5570 return(ret);
5571}
5572
5573/**
5574 * xmlValidatePopElement:
5575 * @ctxt: the validation context
5576 * @doc: a document instance
5577 * @elem: an element instance
5578 * @qname: the qualified name as appearing in the serialization
5579 *
5580 * Pop the element end from the validation stack.
5581 *
5582 * returns 1 if no validation problem was found or 0 otherwise
5583 */
5584int
5585xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005586 xmlNodePtr elem ATTRIBUTE_UNUSED,
5587 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005588 int ret = 1;
5589
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005590/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005591 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5592 xmlValidStatePtr state = ctxt->vstate;
5593 xmlElementPtr elemDecl;
5594
5595 /*
5596 * Check the new element agaisnt the content model of the new elem.
5597 */
5598 if (state->elemDecl != NULL) {
5599 elemDecl = state->elemDecl;
5600
5601 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5602 if (state->exec != NULL) {
5603 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5604 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005605 xmlErrValidNode(ctxt, state->node,
5606 XML_DTD_CONTENT_MODEL,
5607 "Element %s content does not follow the DTD, Expecting more child\n",
5608 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005609 } else {
5610 /*
5611 * previous validation errors should not generate
5612 * a new one here
5613 */
5614 ret = 1;
5615 }
5616 }
5617 }
5618 }
5619 vstateVPop(ctxt);
5620 }
5621 return(ret);
5622}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005623#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005624
5625/**
Owen Taylor3473f882001-02-23 17:55:21 +00005626 * xmlValidateOneElement:
5627 * @ctxt: the validation context
5628 * @doc: a document instance
5629 * @elem: an element instance
5630 *
5631 * Try to validate a single element and it's attributes,
5632 * basically it does the following checks as described by the
5633 * XML-1.0 recommendation:
5634 * - [ VC: Element Valid ]
5635 * - [ VC: Required Attribute ]
5636 * Then call xmlValidateOneAttribute() for each attribute present.
5637 *
5638 * The ID/IDREF checkings are done separately
5639 *
5640 * returns 1 if valid or 0 otherwise
5641 */
5642
5643int
5644xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5645 xmlNodePtr elem) {
5646 xmlElementPtr elemDecl = NULL;
5647 xmlElementContentPtr cont;
5648 xmlAttributePtr attr;
5649 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005650 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005651 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005652 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005653
5654 CHECK_DTD;
5655
5656 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005657 switch (elem->type) {
5658 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005659 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5660 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005661 return(0);
5662 case XML_TEXT_NODE:
5663 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005664 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5665 "Text element has children !\n",
5666 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005667 return(0);
5668 }
5669 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005670 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5671 "Text element has attribute !\n",
5672 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005673 return(0);
5674 }
5675 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005676 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5677 "Text element has namespace !\n",
5678 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005679 return(0);
5680 }
5681 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005682 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5683 "Text element has namespace !\n",
5684 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005685 return(0);
5686 }
5687 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005688 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5689 "Text element has no content !\n",
5690 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005691 return(0);
5692 }
5693 return(1);
5694 case XML_XINCLUDE_START:
5695 case XML_XINCLUDE_END:
5696 return(1);
5697 case XML_CDATA_SECTION_NODE:
5698 case XML_ENTITY_REF_NODE:
5699 case XML_PI_NODE:
5700 case XML_COMMENT_NODE:
5701 return(1);
5702 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005703 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5704 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005705 return(0);
5706 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005707 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5708 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005709 return(0);
5710 case XML_DOCUMENT_NODE:
5711 case XML_DOCUMENT_TYPE_NODE:
5712 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005713 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5714 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005715 return(0);
5716 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005717 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5718 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005719 return(0);
5720 case XML_ELEMENT_NODE:
5721 break;
5722 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005723 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5724 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005725 return(0);
5726 }
Owen Taylor3473f882001-02-23 17:55:21 +00005727
5728 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005729 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005730 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005731 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5732 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005733 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005734
Daniel Veillardea7751d2002-12-20 00:16:24 +00005735 /*
5736 * If vstateNr is not zero that means continuous validation is
5737 * activated, do not try to check the content model at that level.
5738 */
5739 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005740 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005741 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005742 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005743 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5744 "No declaration for element %s\n",
5745 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005746 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005747 case XML_ELEMENT_TYPE_EMPTY:
5748 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005749 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005750 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005751 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005752 ret = 0;
5753 }
5754 break;
5755 case XML_ELEMENT_TYPE_ANY:
5756 /* I don't think anything is required then */
5757 break;
5758 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005759
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005760 /* simple case of declared as #PCDATA */
5761 if ((elemDecl->content != NULL) &&
5762 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5763 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5764 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005765 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005766 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005767 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005768 }
5769 break;
5770 }
Owen Taylor3473f882001-02-23 17:55:21 +00005771 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005772 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005773 while (child != NULL) {
5774 if (child->type == XML_ELEMENT_NODE) {
5775 name = child->name;
5776 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005777 xmlChar fn[50];
5778 xmlChar *fullname;
5779
5780 fullname = xmlBuildQName(child->name, child->ns->prefix,
5781 fn, 50);
5782 if (fullname == NULL)
5783 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005784 cont = elemDecl->content;
5785 while (cont != NULL) {
5786 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005787 if (xmlStrEqual(cont->name, fullname))
5788 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005789 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5790 (cont->c1 != NULL) &&
5791 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005792 if (xmlStrEqual(cont->c1->name, fullname))
5793 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005794 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5795 (cont->c1 == NULL) ||
5796 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005797 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5798 "Internal: MIXED struct corrupted\n",
5799 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005800 break;
5801 }
5802 cont = cont->c2;
5803 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005804 if ((fullname != fn) && (fullname != child->name))
5805 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005806 if (cont != NULL)
5807 goto child_ok;
5808 }
5809 cont = elemDecl->content;
5810 while (cont != NULL) {
5811 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5812 if (xmlStrEqual(cont->name, name)) break;
5813 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5814 (cont->c1 != NULL) &&
5815 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5816 if (xmlStrEqual(cont->c1->name, name)) break;
5817 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5818 (cont->c1 == NULL) ||
5819 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005820 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5821 "Internal: MIXED struct corrupted\n",
5822 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005823 break;
5824 }
5825 cont = cont->c2;
5826 }
5827 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005828 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00005829 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005830 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005831 ret = 0;
5832 }
5833 }
5834child_ok:
5835 child = child->next;
5836 }
5837 break;
5838 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005839 if ((doc->standalone == 1) && (extsubset == 1)) {
5840 /*
5841 * VC: Standalone Document Declaration
5842 * - element types with element content, if white space
5843 * occurs directly within any instance of those types.
5844 */
5845 child = elem->children;
5846 while (child != NULL) {
5847 if (child->type == XML_TEXT_NODE) {
5848 const xmlChar *content = child->content;
5849
William M. Brack76e95df2003-10-18 16:20:14 +00005850 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005851 content++;
5852 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005853 xmlErrValidNode(ctxt, elem,
5854 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005855"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005856 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005857 ret = 0;
5858 break;
5859 }
5860 }
5861 child =child->next;
5862 }
5863 }
Owen Taylor3473f882001-02-23 17:55:21 +00005864 child = elem->children;
5865 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005866 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005867 if (tmp <= 0)
5868 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005869 break;
5870 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005871 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00005872
5873 /* [ VC: Required Attribute ] */
5874 attr = elemDecl->attributes;
5875 while (attr != NULL) {
5876 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005877 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005878
Daniel Veillarde4301c82002-02-13 13:32:35 +00005879 if ((attr->prefix == NULL) &&
5880 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5881 xmlNsPtr ns;
5882
5883 ns = elem->nsDef;
5884 while (ns != NULL) {
5885 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005886 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005887 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00005888 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005889 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5890 xmlNsPtr ns;
5891
5892 ns = elem->nsDef;
5893 while (ns != NULL) {
5894 if (xmlStrEqual(attr->name, ns->prefix))
5895 goto found;
5896 ns = ns->next;
5897 }
5898 } else {
5899 xmlAttrPtr attrib;
5900
5901 attrib = elem->properties;
5902 while (attrib != NULL) {
5903 if (xmlStrEqual(attrib->name, attr->name)) {
5904 if (attr->prefix != NULL) {
5905 xmlNsPtr nameSpace = attrib->ns;
5906
5907 if (nameSpace == NULL)
5908 nameSpace = elem->ns;
5909 /*
5910 * qualified names handling is problematic, having a
5911 * different prefix should be possible but DTDs don't
5912 * allow to define the URI instead of the prefix :-(
5913 */
5914 if (nameSpace == NULL) {
5915 if (qualified < 0)
5916 qualified = 0;
5917 } else if (!xmlStrEqual(nameSpace->prefix,
5918 attr->prefix)) {
5919 if (qualified < 1)
5920 qualified = 1;
5921 } else
5922 goto found;
5923 } else {
5924 /*
5925 * We should allow applications to define namespaces
5926 * for their application even if the DTD doesn't
5927 * carry one, otherwise, basically we would always
5928 * break.
5929 */
5930 goto found;
5931 }
5932 }
5933 attrib = attrib->next;
5934 }
Owen Taylor3473f882001-02-23 17:55:21 +00005935 }
5936 if (qualified == -1) {
5937 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005938 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005939 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005940 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005941 ret = 0;
5942 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005943 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005944 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005945 elem->name, attr->prefix,attr->name);
5946 ret = 0;
5947 }
5948 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005949 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005950 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005951 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005952 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005953 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005954 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005955 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005956 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005957 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5958 /*
5959 * Special tests checking #FIXED namespace declarations
5960 * have the right value since this is not done as an
5961 * attribute checking
5962 */
5963 if ((attr->prefix == NULL) &&
5964 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5965 xmlNsPtr ns;
5966
5967 ns = elem->nsDef;
5968 while (ns != NULL) {
5969 if (ns->prefix == NULL) {
5970 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005971 xmlErrValidNode(ctxt, elem,
5972 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00005973 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005974 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005975 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005976 }
5977 goto found;
5978 }
5979 ns = ns->next;
5980 }
5981 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5982 xmlNsPtr ns;
5983
5984 ns = elem->nsDef;
5985 while (ns != NULL) {
5986 if (xmlStrEqual(attr->name, ns->prefix)) {
5987 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005988 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005989 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005990 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005991 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005992 }
5993 goto found;
5994 }
5995 ns = ns->next;
5996 }
5997 }
Owen Taylor3473f882001-02-23 17:55:21 +00005998 }
5999found:
6000 attr = attr->nexth;
6001 }
6002 return(ret);
6003}
6004
6005/**
6006 * xmlValidateRoot:
6007 * @ctxt: the validation context
6008 * @doc: a document instance
6009 *
6010 * Try to validate a the root element
6011 * basically it does the following check as described by the
6012 * XML-1.0 recommendation:
6013 * - [ VC: Root Element Type ]
6014 * it doesn't try to recurse or apply other check to the element
6015 *
6016 * returns 1 if valid or 0 otherwise
6017 */
6018
6019int
6020xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6021 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006022 int ret;
6023
Owen Taylor3473f882001-02-23 17:55:21 +00006024 if (doc == NULL) return(0);
6025
6026 root = xmlDocGetRootElement(doc);
6027 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006028 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6029 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006030 return(0);
6031 }
6032
6033 /*
6034 * When doing post validation against a separate DTD, those may
6035 * no internal subset has been generated
6036 */
6037 if ((doc->intSubset != NULL) &&
6038 (doc->intSubset->name != NULL)) {
6039 /*
6040 * Check first the document root against the NQName
6041 */
6042 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6043 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006044 xmlChar fn[50];
6045 xmlChar *fullname;
6046
6047 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6048 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006049 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006050 return(0);
6051 }
6052 ret = xmlStrEqual(doc->intSubset->name, fullname);
6053 if ((fullname != fn) && (fullname != root->name))
6054 xmlFree(fullname);
6055 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006056 goto name_ok;
6057 }
6058 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6059 (xmlStrEqual(root->name, BAD_CAST "html")))
6060 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006061 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6062 "root and DTD name do not match '%s' and '%s'\n",
6063 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006064 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006065 }
6066 }
6067name_ok:
6068 return(1);
6069}
6070
6071
6072/**
6073 * xmlValidateElement:
6074 * @ctxt: the validation context
6075 * @doc: a document instance
6076 * @elem: an element instance
6077 *
6078 * Try to validate the subtree under an element
6079 *
6080 * returns 1 if valid or 0 otherwise
6081 */
6082
6083int
6084xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6085 xmlNodePtr child;
6086 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006087 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006088 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006089 int ret = 1;
6090
6091 if (elem == NULL) return(0);
6092
6093 /*
6094 * XInclude elements were added after parsing in the infoset,
6095 * they don't really mean anything validation wise.
6096 */
6097 if ((elem->type == XML_XINCLUDE_START) ||
6098 (elem->type == XML_XINCLUDE_END))
6099 return(1);
6100
6101 CHECK_DTD;
6102
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006103 /*
6104 * Entities references have to be handled separately
6105 */
6106 if (elem->type == XML_ENTITY_REF_NODE) {
6107 return(1);
6108 }
6109
Owen Taylor3473f882001-02-23 17:55:21 +00006110 ret &= xmlValidateOneElement(ctxt, doc, elem);
6111 attr = elem->properties;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006112 while (attr != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006113 value = xmlNodeListGetString(doc, attr->children, 0);
6114 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6115 if (value != NULL)
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006116 xmlFree((char *)value);
Owen Taylor3473f882001-02-23 17:55:21 +00006117 attr= attr->next;
6118 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006119 ns = elem->nsDef;
6120 while (ns != NULL) {
Daniel Veillard1f5c9892003-12-29 17:09:55 +00006121 if (elem->ns == NULL)
6122 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6123 ns, ns->href);
6124 else
6125 ret &= xmlValidateOneNamespace(ctxt, doc, elem, elem->ns->prefix,
6126 ns, ns->href);
Daniel Veillarde133dd82003-10-30 10:42:20 +00006127 ns = ns->next;
6128 }
Owen Taylor3473f882001-02-23 17:55:21 +00006129 child = elem->children;
6130 while (child != NULL) {
6131 ret &= xmlValidateElement(ctxt, doc, child);
6132 child = child->next;
6133 }
6134
6135 return(ret);
6136}
6137
Daniel Veillard8730c562001-02-26 10:49:57 +00006138/**
6139 * xmlValidateRef:
6140 * @ref: A reference to be validated
6141 * @ctxt: Validation context
6142 * @name: Name of ID we are searching for
6143 *
6144 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006145static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006146xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006147 const xmlChar *name) {
6148 xmlAttrPtr id;
6149 xmlAttrPtr attr;
6150
6151 if (ref == NULL)
6152 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006153 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006154 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006155 attr = ref->attr;
6156 if (attr == NULL) {
6157 xmlChar *dup, *str = NULL, *cur, save;
6158
6159 dup = xmlStrdup(name);
6160 if (dup == NULL) {
6161 ctxt->valid = 0;
6162 return;
6163 }
6164 cur = dup;
6165 while (*cur != 0) {
6166 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006167 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006168 save = *cur;
6169 *cur = 0;
6170 id = xmlGetID(ctxt->doc, str);
6171 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006172 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006173 "attribute %s line %d references an unknown ID \"%s\"\n",
6174 ref->name, ref->lineno, str);
6175 ctxt->valid = 0;
6176 }
6177 if (save == 0)
6178 break;
6179 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006180 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006181 }
6182 xmlFree(dup);
6183 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006184 id = xmlGetID(ctxt->doc, name);
6185 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006186 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006187 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006188 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006189 ctxt->valid = 0;
6190 }
6191 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6192 xmlChar *dup, *str = NULL, *cur, save;
6193
6194 dup = xmlStrdup(name);
6195 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006196 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006197 ctxt->valid = 0;
6198 return;
6199 }
6200 cur = dup;
6201 while (*cur != 0) {
6202 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006203 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006204 save = *cur;
6205 *cur = 0;
6206 id = xmlGetID(ctxt->doc, str);
6207 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006208 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006209 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006210 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006211 ctxt->valid = 0;
6212 }
6213 if (save == 0)
6214 break;
6215 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006216 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006217 }
6218 xmlFree(dup);
6219 }
6220}
6221
6222/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006223 * xmlWalkValidateList:
6224 * @data: Contents of current link
6225 * @user: Value supplied by the user
6226 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006227 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006228 */
6229static int
6230xmlWalkValidateList(const void *data, const void *user)
6231{
6232 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6233 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6234 return 1;
6235}
6236
6237/**
6238 * xmlValidateCheckRefCallback:
6239 * @ref_list: List of references
6240 * @ctxt: Validation context
6241 * @name: Name of ID we are searching for
6242 *
6243 */
6244static void
6245xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6246 const xmlChar *name) {
6247 xmlValidateMemo memo;
6248
6249 if (ref_list == NULL)
6250 return;
6251 memo.ctxt = ctxt;
6252 memo.name = name;
6253
6254 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6255
6256}
6257
6258/**
Owen Taylor3473f882001-02-23 17:55:21 +00006259 * xmlValidateDocumentFinal:
6260 * @ctxt: the validation context
6261 * @doc: a document instance
6262 *
6263 * Does the final step for the document validation once all the
6264 * incremental validation steps have been completed
6265 *
6266 * basically it does the following checks described by the XML Rec
6267 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006268 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006269 *
6270 * returns 1 if valid or 0 otherwise
6271 */
6272
6273int
6274xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6275 xmlRefTablePtr table;
6276
6277 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006278 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6279 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006280 return(0);
6281 }
6282
6283 /*
6284 * Check all the NOTATION/NOTATIONS attributes
6285 */
6286 /*
6287 * Check all the ENTITY/ENTITIES attributes definition for validity
6288 */
6289 /*
6290 * Check all the IDREF/IDREFS attributes definition for validity
6291 */
6292 table = (xmlRefTablePtr) doc->refs;
6293 ctxt->doc = doc;
6294 ctxt->valid = 1;
6295 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6296 return(ctxt->valid);
6297}
6298
6299/**
6300 * xmlValidateDtd:
6301 * @ctxt: the validation context
6302 * @doc: a document instance
6303 * @dtd: a dtd instance
6304 *
6305 * Try to validate the document against the dtd instance
6306 *
William M. Brack367df6e2004-10-23 18:14:36 +00006307 * Basically it does check all the definitions in the DtD.
6308 * Note the the internal subset (if present) is de-coupled
6309 * (i.e. not used), which could give problems if ID or IDREF
6310 * is present.
Owen Taylor3473f882001-02-23 17:55:21 +00006311 *
6312 * returns 1 if valid or 0 otherwise
6313 */
6314
6315int
6316xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6317 int ret;
William M. Brack367df6e2004-10-23 18:14:36 +00006318 xmlDtdPtr oldExt, oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006319 xmlNodePtr root;
6320
6321 if (dtd == NULL) return(0);
6322 if (doc == NULL) return(0);
6323 oldExt = doc->extSubset;
William M. Brack367df6e2004-10-23 18:14:36 +00006324 oldInt = doc->intSubset;
Owen Taylor3473f882001-02-23 17:55:21 +00006325 doc->extSubset = dtd;
William M. Brack367df6e2004-10-23 18:14:36 +00006326 doc->intSubset = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006327 ret = xmlValidateRoot(ctxt, doc);
6328 if (ret == 0) {
6329 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006330 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006331 return(ret);
6332 }
6333 if (doc->ids != NULL) {
6334 xmlFreeIDTable(doc->ids);
6335 doc->ids = NULL;
6336 }
6337 if (doc->refs != NULL) {
6338 xmlFreeRefTable(doc->refs);
6339 doc->refs = NULL;
6340 }
6341 root = xmlDocGetRootElement(doc);
6342 ret = xmlValidateElement(ctxt, doc, root);
6343 ret &= xmlValidateDocumentFinal(ctxt, doc);
6344 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006345 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006346 return(ret);
6347}
6348
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006349static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006350xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6351 const xmlChar *name ATTRIBUTE_UNUSED) {
6352 if (cur == NULL)
6353 return;
6354 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6355 xmlChar *notation = cur->content;
6356
Daniel Veillard878eab02002-02-19 13:46:09 +00006357 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006358 int ret;
6359
6360 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6361 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006362 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006363 }
6364 }
6365 }
6366}
6367
6368static void
Owen Taylor3473f882001-02-23 17:55:21 +00006369xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006370 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006371 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006372 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006373 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006374
Owen Taylor3473f882001-02-23 17:55:21 +00006375 if (cur == NULL)
6376 return;
6377 switch (cur->atype) {
6378 case XML_ATTRIBUTE_CDATA:
6379 case XML_ATTRIBUTE_ID:
6380 case XML_ATTRIBUTE_IDREF :
6381 case XML_ATTRIBUTE_IDREFS:
6382 case XML_ATTRIBUTE_NMTOKEN:
6383 case XML_ATTRIBUTE_NMTOKENS:
6384 case XML_ATTRIBUTE_ENUMERATION:
6385 break;
6386 case XML_ATTRIBUTE_ENTITY:
6387 case XML_ATTRIBUTE_ENTITIES:
6388 case XML_ATTRIBUTE_NOTATION:
6389 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006390
6391 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6392 cur->atype, cur->defaultValue);
6393 if ((ret == 0) && (ctxt->valid == 1))
6394 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006395 }
6396 if (cur->tree != NULL) {
6397 xmlEnumerationPtr tree = cur->tree;
6398 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006399 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006400 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006401 if ((ret == 0) && (ctxt->valid == 1))
6402 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006403 tree = tree->next;
6404 }
6405 }
6406 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006407 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6408 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006409 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006410 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006411 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006412 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006413 return;
6414 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006415
6416 if (doc != NULL)
6417 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6418 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006419 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006420 if ((elem == NULL) && (cur->parent != NULL) &&
6421 (cur->parent->type == XML_DTD_NODE))
6422 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006423 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006424 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006425 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006426 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006427 return;
6428 }
6429 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006430 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006431 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006432 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006433 ctxt->valid = 0;
6434 }
6435 }
Owen Taylor3473f882001-02-23 17:55:21 +00006436}
6437
6438/**
6439 * xmlValidateDtdFinal:
6440 * @ctxt: the validation context
6441 * @doc: a document instance
6442 *
6443 * Does the final step for the dtds validation once all the
6444 * subsets have been parsed
6445 *
6446 * basically it does the following checks described by the XML Rec
6447 * - check that ENTITY and ENTITIES type attributes default or
6448 * possible values matches one of the defined entities.
6449 * - check that NOTATION type attributes default or
6450 * possible values matches one of the defined notations.
6451 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006452 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006453 */
6454
6455int
6456xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006457 xmlDtdPtr dtd;
6458 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006459 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006460
6461 if (doc == NULL) return(0);
6462 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6463 return(0);
6464 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006465 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006466 dtd = doc->intSubset;
6467 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6468 table = (xmlAttributeTablePtr) dtd->attributes;
6469 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006470 }
6471 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006472 entities = (xmlEntitiesTablePtr) dtd->entities;
6473 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6474 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006475 }
6476 dtd = doc->extSubset;
6477 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6478 table = (xmlAttributeTablePtr) dtd->attributes;
6479 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006480 }
6481 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006482 entities = (xmlEntitiesTablePtr) dtd->entities;
6483 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6484 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006485 }
6486 return(ctxt->valid);
6487}
6488
6489/**
6490 * xmlValidateDocument:
6491 * @ctxt: the validation context
6492 * @doc: a document instance
6493 *
6494 * Try to validate the document instance
6495 *
6496 * basically it does the all the checks described by the XML Rec
6497 * i.e. validates the internal and external subset (if present)
6498 * and validate the document tree.
6499 *
6500 * returns 1 if valid or 0 otherwise
6501 */
6502
6503int
6504xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6505 int ret;
6506 xmlNodePtr root;
6507
Daniel Veillard2fd85422002-10-16 14:32:41 +00006508 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006509 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6510 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006511 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006512 }
Owen Taylor3473f882001-02-23 17:55:21 +00006513 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6514 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
William M. Brack8c22f9f2004-08-06 16:23:27 +00006515 xmlChar *sysID;
6516 if (doc->intSubset->SystemID != NULL) {
William M. Brackbebe7302004-08-05 06:46:47 +00006517 sysID = xmlBuildURI(doc->intSubset->SystemID,
6518 doc->URL);
William M. Brack8c22f9f2004-08-06 16:23:27 +00006519 if (sysID == NULL) {
6520 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6521 "Could not build URI for external subset \"%s\"\n",
6522 (const char *) doc->intSubset->SystemID);
6523 return 0;
6524 }
6525 } else
William M. Brackbebe7302004-08-05 06:46:47 +00006526 sysID = NULL;
William M. Brack8c22f9f2004-08-06 16:23:27 +00006527 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
William M. Brackbebe7302004-08-05 06:46:47 +00006528 (const xmlChar *)sysID);
William M. Brackbebe7302004-08-05 06:46:47 +00006529 if (sysID != NULL)
6530 xmlFree(sysID);
Owen Taylor3473f882001-02-23 17:55:21 +00006531 if (doc->extSubset == NULL) {
6532 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006533 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006534 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006535 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006536 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006537 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006538 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006539 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006540 }
6541 return(0);
6542 }
6543 }
6544
6545 if (doc->ids != NULL) {
6546 xmlFreeIDTable(doc->ids);
6547 doc->ids = NULL;
6548 }
6549 if (doc->refs != NULL) {
6550 xmlFreeRefTable(doc->refs);
6551 doc->refs = NULL;
6552 }
6553 ret = xmlValidateDtdFinal(ctxt, doc);
6554 if (!xmlValidateRoot(ctxt, doc)) return(0);
6555
6556 root = xmlDocGetRootElement(doc);
6557 ret &= xmlValidateElement(ctxt, doc, root);
6558 ret &= xmlValidateDocumentFinal(ctxt, doc);
6559 return(ret);
6560}
6561
Owen Taylor3473f882001-02-23 17:55:21 +00006562/************************************************************************
6563 * *
6564 * Routines for dynamic validation editing *
6565 * *
6566 ************************************************************************/
6567
6568/**
6569 * xmlValidGetPotentialChildren:
6570 * @ctree: an element content tree
6571 * @list: an array to store the list of child names
6572 * @len: a pointer to the number of element in the list
6573 * @max: the size of the array
6574 *
6575 * Build/extend a list of potential children allowed by the content tree
6576 *
6577 * returns the number of element in the list, or -1 in case of error.
6578 */
6579
6580int
6581xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6582 int *len, int max) {
6583 int i;
6584
6585 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6586 return(-1);
6587 if (*len >= max) return(*len);
6588
6589 switch (ctree->type) {
6590 case XML_ELEMENT_CONTENT_PCDATA:
6591 for (i = 0; i < *len;i++)
6592 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6593 list[(*len)++] = BAD_CAST "#PCDATA";
6594 break;
6595 case XML_ELEMENT_CONTENT_ELEMENT:
6596 for (i = 0; i < *len;i++)
6597 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6598 list[(*len)++] = ctree->name;
6599 break;
6600 case XML_ELEMENT_CONTENT_SEQ:
6601 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6602 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6603 break;
6604 case XML_ELEMENT_CONTENT_OR:
6605 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6606 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6607 break;
6608 }
6609
6610 return(*len);
6611}
6612
William M. Brack9333cc22004-06-24 08:33:40 +00006613/*
6614 * Dummy function to suppress messages while we try out valid elements
6615 */
6616static void xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
6617 const char *msg ATTRIBUTE_UNUSED, ...) {
6618 return;
6619}
6620
Owen Taylor3473f882001-02-23 17:55:21 +00006621/**
6622 * xmlValidGetValidElements:
6623 * @prev: an element to insert after
6624 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006625 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006626 * @max: the size of the array
6627 *
6628 * This function returns the list of authorized children to insert
6629 * within an existing tree while respecting the validity constraints
6630 * forced by the Dtd. The insertion point is defined using @prev and
6631 * @next in the following ways:
6632 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6633 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6634 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6635 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6636 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6637 *
6638 * pointers to the element names are inserted at the beginning of the array
6639 * and do not need to be freed.
6640 *
6641 * returns the number of element in the list, or -1 in case of error. If
6642 * the function returns the value @max the caller is invited to grow the
6643 * receiving array and retry.
6644 */
6645
6646int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006647xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006648 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006649 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006650 int nb_valid_elements = 0;
6651 const xmlChar *elements[256];
6652 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006653 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006654
6655 xmlNode *ref_node;
6656 xmlNode *parent;
6657 xmlNode *test_node;
6658
6659 xmlNode *prev_next;
6660 xmlNode *next_prev;
6661 xmlNode *parent_childs;
6662 xmlNode *parent_last;
6663
6664 xmlElement *element_desc;
6665
6666 if (prev == NULL && next == NULL)
6667 return(-1);
6668
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006669 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006670 if (max <= 0) return(-1);
6671
William M. Brack9333cc22004-06-24 08:33:40 +00006672 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6673 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6674
Owen Taylor3473f882001-02-23 17:55:21 +00006675 nb_valid_elements = 0;
6676 ref_node = prev ? prev : next;
6677 parent = ref_node->parent;
6678
6679 /*
6680 * Retrieves the parent element declaration
6681 */
6682 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6683 parent->name);
6684 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6685 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6686 parent->name);
6687 if (element_desc == NULL) return(-1);
6688
6689 /*
6690 * Do a backup of the current tree structure
6691 */
6692 prev_next = prev ? prev->next : NULL;
6693 next_prev = next ? next->prev : NULL;
6694 parent_childs = parent->children;
6695 parent_last = parent->last;
6696
6697 /*
6698 * Creates a dummy node and insert it into the tree
6699 */
6700 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
6701 test_node->doc = ref_node->doc;
6702 test_node->parent = parent;
6703 test_node->prev = prev;
6704 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006705 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006706
6707 if (prev) prev->next = test_node;
6708 else parent->children = test_node;
6709
6710 if (next) next->prev = test_node;
6711 else parent->last = test_node;
6712
6713 /*
6714 * Insert each potential child node and check if the parent is
6715 * still valid
6716 */
6717 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6718 elements, &nb_elements, 256);
6719
6720 for (i = 0;i < nb_elements;i++) {
6721 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006722 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006723 int j;
6724
6725 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006726 if (xmlStrEqual(elements[i], names[j])) break;
6727 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00006728 if (nb_valid_elements >= max) break;
6729 }
6730 }
6731
6732 /*
6733 * Restore the tree structure
6734 */
6735 if (prev) prev->next = prev_next;
6736 if (next) next->prev = next_prev;
6737 parent->children = parent_childs;
6738 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006739
6740 /*
6741 * Free up the dummy node
6742 */
6743 test_node->name = name;
6744 xmlFreeNode(test_node);
6745
Owen Taylor3473f882001-02-23 17:55:21 +00006746 return(nb_valid_elements);
6747}
Daniel Veillard4432df22003-09-28 18:58:27 +00006748#endif /* LIBXML_VALID_ENABLED */
6749