blob: 22e41e6fa8a8985113ad60e09bc3b1650e8fa72f [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>
21#include <libxml/valid.h>
22#include <libxml/parser.h>
23#include <libxml/parserInternals.h>
24#include <libxml/xmlerror.h>
25#include <libxml/list.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000026#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000027
Daniel Veillard4432df22003-09-28 18:58:27 +000028static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
29 int create);
Daniel Veillarde62d36c2001-05-15 08:53:16 +000030/* #define DEBUG_VALID_ALGO */
Daniel Veillard5acfd6b2002-09-18 16:29:02 +000031/* #define DEBUG_REGEXP_ALGO */
Daniel Veillarde62d36c2001-05-15 08:53:16 +000032
Daniel Veillarda646cfd2002-09-17 21:50:03 +000033#define TODO \
34 xmlGenericError(xmlGenericErrorContext, \
35 "Unimplemented block at %s:%d\n", \
36 __FILE__, __LINE__);
Owen Taylor3473f882001-02-23 17:55:21 +000037
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000038/************************************************************************
39 * *
40 * Error handling routines *
41 * *
42 ************************************************************************/
43
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000044/**
Daniel Veillardce9457f2003-10-05 21:33:18 +000045 * xmlVErrMemory:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000046 * @ctxt: an XML validation parser context
47 * @extra: extra informations
48 *
49 * Handle an out of memory error
50 */
51static void
Daniel Veillardce9457f2003-10-05 21:33:18 +000052xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000053{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000054 xmlGenericErrorFunc channel = NULL;
55 xmlParserCtxtPtr pctxt = NULL;
56 void *data = NULL;
57
58 if (ctxt != NULL) {
59 channel = ctxt->error;
60 data = ctxt->userData;
61 pctxt = ctxt->userData;
62 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000063 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000064 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000065 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000066 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
67 "Memory allocation failed : %s\n", extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000068 else
Daniel Veillard73000572003-10-11 11:26:42 +000069 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000070 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000071 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
72 "Memory allocation failed\n");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000073}
74
75/**
76 * xmlErrValid:
77 * @ctxt: an XML validation parser context
Daniel Veillardbb5abab2003-10-03 22:21:51 +000078 * @error: the error number
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000079 * @extra: extra informations
80 *
81 * Handle a validation error
82 */
83static void
Daniel Veillardf88d8cf2003-12-08 10:25:02 +000084xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000085 const char *msg, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000086{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000087 xmlGenericErrorFunc channel = NULL;
88 xmlParserCtxtPtr pctxt = NULL;
89 void *data = NULL;
90
91 if (ctxt != NULL) {
92 channel = ctxt->error;
93 data = ctxt->userData;
94 pctxt = ctxt->userData;
95 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000096 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000097 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000098 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000099 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
100 msg, extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000101 else
Daniel Veillard73000572003-10-11 11:26:42 +0000102 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000103 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000104 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
105 msg);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000106}
107
Daniel Veillardd61e8fb2003-10-19 21:59:17 +0000108#ifdef LIBXML_VALID_ENABLED
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000109/**
110 * xmlErrValidNodeNr:
111 * @ctxt: an XML validation parser context
112 * @node: the node raising the error
113 * @error: the error number
114 * @str1: extra informations
115 * @int2: extra informations
116 * @str3: extra informations
117 *
118 * Handle a validation error, provide contextual informations
119 */
120static void
Daniel Veillard72b9e292003-10-28 15:44:17 +0000121xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000122 xmlNodePtr node, xmlParserErrors error,
123 const char *msg, const xmlChar * str1,
124 int int2, const xmlChar * str3)
125{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000126 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000127 xmlGenericErrorFunc channel = NULL;
128 xmlParserCtxtPtr pctxt = NULL;
129 void *data = NULL;
130
131 if (ctxt != NULL) {
132 channel = ctxt->error;
133 data = ctxt->userData;
134 pctxt = ctxt->userData;
135 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000136 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000137 XML_ERR_ERROR, NULL, 0,
138 (const char *) str1,
139 (const char *) str3,
140 NULL, int2, 0, msg, str1, int2, str3);
141}
142/**
143 * xmlErrValidNode:
144 * @ctxt: an XML validation parser context
145 * @node: the node raising the error
146 * @error: the error number
147 * @str1: extra informations
148 * @str2: extra informations
149 * @str3: extra informations
150 *
151 * Handle a validation error, provide contextual informations
152 */
153static void
William M. Brackedb65a72004-02-06 07:36:04 +0000154xmlErrValidNode(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000155 xmlNodePtr node, xmlParserErrors error,
156 const char *msg, const xmlChar * str1,
157 const xmlChar * str2, const xmlChar * str3)
158{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000159 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000160 xmlGenericErrorFunc channel = NULL;
161 xmlParserCtxtPtr pctxt = NULL;
162 void *data = NULL;
163
164 if (ctxt != NULL) {
165 channel = ctxt->error;
166 data = ctxt->userData;
167 pctxt = ctxt->userData;
168 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000169 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000170 XML_ERR_ERROR, NULL, 0,
171 (const char *) str1,
172 (const char *) str1,
173 (const char *) str3, 0, 0, msg, str1, str2, str3);
174}
175/**
176 * xmlErrValidWarning:
177 * @ctxt: an XML validation parser context
178 * @node: the node raising the error
179 * @error: the error number
William M. Brackedb65a72004-02-06 07:36:04 +0000180 * @str1: extra information
181 * @str2: extra information
182 * @str3: extra information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000183 *
William M. Brackedb65a72004-02-06 07:36:04 +0000184 * Handle a validation error, provide contextual information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000185 */
186static void
William M. Brackedb65a72004-02-06 07:36:04 +0000187xmlErrValidWarning(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000188 xmlNodePtr node, xmlParserErrors error,
189 const char *msg, const xmlChar * str1,
190 const xmlChar * str2, const xmlChar * str3)
191{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000192 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000193 xmlGenericErrorFunc channel = NULL;
194 xmlParserCtxtPtr pctxt = NULL;
195 void *data = NULL;
196
197 if (ctxt != NULL) {
198 channel = ctxt->error;
199 data = ctxt->userData;
200 pctxt = ctxt->userData;
201 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000202 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000203 XML_ERR_WARNING, NULL, 0,
204 (const char *) str1,
205 (const char *) str1,
206 (const char *) str3, 0, 0, msg, str1, str2, str3);
207}
208
209
Daniel Veillardea7751d2002-12-20 00:16:24 +0000210
211#ifdef LIBXML_REGEXP_ENABLED
212/*
213 * If regexp are enabled we can do continuous validation without the
214 * need of a tree to validate the content model. this is done in each
215 * callbacks.
216 * Each xmlValidState represent the validation state associated to the
217 * set of nodes currently open from the document root to the current element.
218 */
219
220
221typedef struct _xmlValidState {
222 xmlElementPtr elemDecl; /* pointer to the content model */
223 xmlNodePtr node; /* pointer to the current node */
224 xmlRegExecCtxtPtr exec; /* regexp runtime */
225} _xmlValidState;
226
227
228static int
229vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000230 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000231 ctxt->vstateMax = 10;
232 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
233 sizeof(ctxt->vstateTab[0]));
234 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000235 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000236 return(-1);
237 }
238 }
239
240 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000241 xmlValidState *tmp;
242
243 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
244 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
245 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000246 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000247 return(-1);
248 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000249 ctxt->vstateMax *= 2;
250 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000251 }
252 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
253 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
254 ctxt->vstateTab[ctxt->vstateNr].node = node;
255 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
256 if (elemDecl->contModel == NULL)
257 xmlValidBuildContentModel(ctxt, elemDecl);
258 if (elemDecl->contModel != NULL) {
259 ctxt->vstateTab[ctxt->vstateNr].exec =
260 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
261 } else {
262 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000263 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
264 XML_ERR_INTERNAL_ERROR,
265 "Failed to build content model regexp for %s\n",
266 node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000267 }
268 }
269 return(ctxt->vstateNr++);
270}
271
272static int
273vstateVPop(xmlValidCtxtPtr ctxt) {
274 xmlElementPtr elemDecl;
275
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000276 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000277 ctxt->vstateNr--;
278 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
279 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
280 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
281 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
282 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
283 }
284 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
285 if (ctxt->vstateNr >= 1)
286 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
287 else
288 ctxt->vstate = NULL;
289 return(ctxt->vstateNr);
290}
291
292#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000293/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000294 * If regexp are not enabled, it uses a home made algorithm less
295 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000296 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000297 * only restriction is on the deepness of the tree limited by the
298 * size of the occurs bitfield
299 *
300 * this is the content of a saved state for rollbacks
301 */
302
303#define ROLLBACK_OR 0
304#define ROLLBACK_PARENT 1
305
Daniel Veillardb44025c2001-10-11 22:55:55 +0000306typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000307 xmlElementContentPtr cont; /* pointer to the content model subtree */
308 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000309 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000310 unsigned char depth; /* current depth in the overall tree */
311 unsigned char state; /* ROLLBACK_XXX */
312} _xmlValidState;
313
Daniel Veillardfc57b412002-04-29 15:50:14 +0000314#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000315#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
316#define CONT ctxt->vstate->cont
317#define NODE ctxt->vstate->node
318#define DEPTH ctxt->vstate->depth
319#define OCCURS ctxt->vstate->occurs
320#define STATE ctxt->vstate->state
321
Daniel Veillard5344c602001-12-31 16:37:34 +0000322#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
323#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000324
Daniel Veillard5344c602001-12-31 16:37:34 +0000325#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
326#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000327
328static int
329vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
330 xmlNodePtr node, unsigned char depth, long occurs,
331 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000332 int i = ctxt->vstateNr - 1;
333
Daniel Veillard940492d2002-04-15 10:15:25 +0000334 if (ctxt->vstateNr > MAX_RECURSE) {
335 return(-1);
336 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000337 if (ctxt->vstateTab == NULL) {
338 ctxt->vstateMax = 8;
339 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
340 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
341 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000342 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000343 return(-1);
344 }
345 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000346 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000347 xmlValidState *tmp;
348
349 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
350 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
351 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000352 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000353 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000354 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000355 ctxt->vstateMax *= 2;
356 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000357 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000358 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000359 /*
360 * Don't push on the stack a state already here
361 */
362 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
363 (ctxt->vstateTab[i].node == node) &&
364 (ctxt->vstateTab[i].depth == depth) &&
365 (ctxt->vstateTab[i].occurs == occurs) &&
366 (ctxt->vstateTab[i].state == state))
367 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000368 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
369 ctxt->vstateTab[ctxt->vstateNr].node = node;
370 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
371 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
372 ctxt->vstateTab[ctxt->vstateNr].state = state;
373 return(ctxt->vstateNr++);
374}
375
376static int
377vstateVPop(xmlValidCtxtPtr ctxt) {
378 if (ctxt->vstateNr <= 1) return(-1);
379 ctxt->vstateNr--;
380 ctxt->vstate = &ctxt->vstateTab[0];
381 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
382 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
383 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
384 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
385 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
386 return(ctxt->vstateNr);
387}
388
Daniel Veillard118aed72002-09-24 14:13:13 +0000389#endif /* LIBXML_REGEXP_ENABLED */
390
Daniel Veillard1c732d22002-11-30 11:22:59 +0000391static int
392nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
393{
394 if (ctxt->nodeMax <= 0) {
395 ctxt->nodeMax = 4;
396 ctxt->nodeTab =
397 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
398 sizeof(ctxt->nodeTab[0]));
399 if (ctxt->nodeTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000400 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000401 ctxt->nodeMax = 0;
402 return (0);
403 }
404 }
405 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000406 xmlNodePtr *tmp;
407 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
408 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
409 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000410 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000411 return (0);
412 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000413 ctxt->nodeMax *= 2;
414 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000415 }
416 ctxt->nodeTab[ctxt->nodeNr] = value;
417 ctxt->node = value;
418 return (ctxt->nodeNr++);
419}
420static xmlNodePtr
421nodeVPop(xmlValidCtxtPtr ctxt)
422{
423 xmlNodePtr ret;
424
425 if (ctxt->nodeNr <= 0)
426 return (0);
427 ctxt->nodeNr--;
428 if (ctxt->nodeNr > 0)
429 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
430 else
431 ctxt->node = NULL;
432 ret = ctxt->nodeTab[ctxt->nodeNr];
433 ctxt->nodeTab[ctxt->nodeNr] = 0;
434 return (ret);
435}
Owen Taylor3473f882001-02-23 17:55:21 +0000436
Owen Taylor3473f882001-02-23 17:55:21 +0000437#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000438static void
439xmlValidPrintNode(xmlNodePtr cur) {
440 if (cur == NULL) {
441 xmlGenericError(xmlGenericErrorContext, "null");
442 return;
443 }
444 switch (cur->type) {
445 case XML_ELEMENT_NODE:
446 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
447 break;
448 case XML_TEXT_NODE:
449 xmlGenericError(xmlGenericErrorContext, "text ");
450 break;
451 case XML_CDATA_SECTION_NODE:
452 xmlGenericError(xmlGenericErrorContext, "cdata ");
453 break;
454 case XML_ENTITY_REF_NODE:
455 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
456 break;
457 case XML_PI_NODE:
458 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
459 break;
460 case XML_COMMENT_NODE:
461 xmlGenericError(xmlGenericErrorContext, "comment ");
462 break;
463 case XML_ATTRIBUTE_NODE:
464 xmlGenericError(xmlGenericErrorContext, "?attr? ");
465 break;
466 case XML_ENTITY_NODE:
467 xmlGenericError(xmlGenericErrorContext, "?ent? ");
468 break;
469 case XML_DOCUMENT_NODE:
470 xmlGenericError(xmlGenericErrorContext, "?doc? ");
471 break;
472 case XML_DOCUMENT_TYPE_NODE:
473 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
474 break;
475 case XML_DOCUMENT_FRAG_NODE:
476 xmlGenericError(xmlGenericErrorContext, "?frag? ");
477 break;
478 case XML_NOTATION_NODE:
479 xmlGenericError(xmlGenericErrorContext, "?nota? ");
480 break;
481 case XML_HTML_DOCUMENT_NODE:
482 xmlGenericError(xmlGenericErrorContext, "?html? ");
483 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000484#ifdef LIBXML_DOCB_ENABLED
485 case XML_DOCB_DOCUMENT_NODE:
486 xmlGenericError(xmlGenericErrorContext, "?docb? ");
487 break;
488#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000489 case XML_DTD_NODE:
490 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
491 break;
492 case XML_ELEMENT_DECL:
493 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
494 break;
495 case XML_ATTRIBUTE_DECL:
496 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
497 break;
498 case XML_ENTITY_DECL:
499 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
500 break;
501 case XML_NAMESPACE_DECL:
502 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
503 break;
504 case XML_XINCLUDE_START:
505 xmlGenericError(xmlGenericErrorContext, "incstart ");
506 break;
507 case XML_XINCLUDE_END:
508 xmlGenericError(xmlGenericErrorContext, "incend ");
509 break;
510 }
511}
512
513static void
514xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000515 if (cur == NULL)
516 xmlGenericError(xmlGenericErrorContext, "null ");
517 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000518 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000519 cur = cur->next;
520 }
521}
522
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000523static void
524xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000525 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000526
527 expr[0] = 0;
528 xmlGenericError(xmlGenericErrorContext, "valid: ");
529 xmlValidPrintNodeList(cur);
530 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000531 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000532 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
533}
534
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000535static void
536xmlValidDebugState(xmlValidStatePtr state) {
537 xmlGenericError(xmlGenericErrorContext, "(");
538 if (state->cont == NULL)
539 xmlGenericError(xmlGenericErrorContext, "null,");
540 else
541 switch (state->cont->type) {
542 case XML_ELEMENT_CONTENT_PCDATA:
543 xmlGenericError(xmlGenericErrorContext, "pcdata,");
544 break;
545 case XML_ELEMENT_CONTENT_ELEMENT:
546 xmlGenericError(xmlGenericErrorContext, "%s,",
547 state->cont->name);
548 break;
549 case XML_ELEMENT_CONTENT_SEQ:
550 xmlGenericError(xmlGenericErrorContext, "seq,");
551 break;
552 case XML_ELEMENT_CONTENT_OR:
553 xmlGenericError(xmlGenericErrorContext, "or,");
554 break;
555 }
556 xmlValidPrintNode(state->node);
557 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
558 state->depth, state->occurs, state->state);
559}
560
561static void
562xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
563 int i, j;
564
565 xmlGenericError(xmlGenericErrorContext, "state: ");
566 xmlValidDebugState(ctxt->vstate);
567 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
568 ctxt->vstateNr - 1);
569 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
570 xmlValidDebugState(&ctxt->vstateTab[j]);
571 xmlGenericError(xmlGenericErrorContext, "\n");
572}
573
574/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000575#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000576 *****/
577
578#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000579#define DEBUG_VALID_MSG(m) \
580 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
581
Owen Taylor3473f882001-02-23 17:55:21 +0000582#else
583#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000584#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000585#endif
586
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000587/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000588
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000589
Owen Taylor3473f882001-02-23 17:55:21 +0000590#define CHECK_DTD \
591 if (doc == NULL) return(0); \
592 else if ((doc->intSubset == NULL) && \
593 (doc->extSubset == NULL)) return(0)
594
Owen Taylor3473f882001-02-23 17:55:21 +0000595xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
596
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000597#ifdef LIBXML_REGEXP_ENABLED
598
599/************************************************************************
600 * *
601 * Content model validation based on the regexps *
602 * *
603 ************************************************************************/
604
605/**
606 * xmlValidBuildAContentModel:
607 * @content: the content model
608 * @ctxt: the schema parser context
609 * @name: the element name whose content is being built
610 *
611 * Generate the automata sequence needed for that type
612 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000613 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000614 */
615static int
616xmlValidBuildAContentModel(xmlElementContentPtr content,
617 xmlValidCtxtPtr ctxt,
618 const xmlChar *name) {
619 if (content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000620 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
621 "Found NULL content in content model of %s\n",
622 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000623 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000624 }
625 switch (content->type) {
626 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000627 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
628 "Found PCDATA in content model of %s\n",
629 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000630 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000631 break;
632 case XML_ELEMENT_CONTENT_ELEMENT: {
633 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000634 xmlChar fn[50];
635 xmlChar *fullname;
636
637 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
638 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000639 xmlVErrMemory(ctxt, "Building content model");
Daniel Veillardc00cda82003-04-07 10:22:39 +0000640 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000641 }
642
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000643 switch (content->ocur) {
644 case XML_ELEMENT_CONTENT_ONCE:
645 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000646 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000647 break;
648 case XML_ELEMENT_CONTENT_OPT:
649 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000650 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000651 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
652 break;
653 case XML_ELEMENT_CONTENT_PLUS:
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 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000657 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000658 break;
659 case XML_ELEMENT_CONTENT_MULT:
660 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000661 ctxt->state, fullname, NULL);
Daniel Veillard57e79b32003-02-04 15:33:12 +0000662 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
663 NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000664 break;
665 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000666 if ((fullname != fn) && (fullname != content->name))
667 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000668 break;
669 }
670 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000671 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000672 xmlElementContentOccur ocur;
673
674 /*
675 * Simply iterate over the content
676 */
677 oldstate = ctxt->state;
678 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000679 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
680 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
681 oldstate = ctxt->state;
682 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000683 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000684 xmlValidBuildAContentModel(content->c1, ctxt, name);
685 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000686 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
687 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
688 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000689 oldend = ctxt->state;
690 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000691 switch (ocur) {
692 case XML_ELEMENT_CONTENT_ONCE:
693 break;
694 case XML_ELEMENT_CONTENT_OPT:
695 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
696 break;
697 case XML_ELEMENT_CONTENT_MULT:
698 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000699 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000700 break;
701 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000702 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000703 break;
704 }
705 break;
706 }
707 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000708 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000709 xmlElementContentOccur ocur;
710
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000711 ocur = content->ocur;
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000712 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
713 (ocur == XML_ELEMENT_CONTENT_MULT)) {
714 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
715 ctxt->state, NULL);
716 }
717 oldstate = ctxt->state;
718 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000719
720 /*
721 * iterate over the subtypes and remerge the end with an
722 * epsilon transition
723 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000724 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000725 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000726 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000727 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000728 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000729 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
730 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000731 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000732 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000733 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
734 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000735 switch (ocur) {
736 case XML_ELEMENT_CONTENT_ONCE:
737 break;
738 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000739 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000740 break;
741 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000742 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
743 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000744 break;
745 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000746 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000747 break;
748 }
749 break;
750 }
751 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000752 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
753 "ContentModel broken for element %s\n",
754 (const char *) name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000755 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000756 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000757 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000758}
759/**
760 * xmlValidBuildContentModel:
761 * @ctxt: a validation context
762 * @elem: an element declaration node
763 *
764 * (Re)Build the automata associated to the content model of this
765 * element
766 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000767 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000768 */
769int
770xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000771
772 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000773 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000774 if (elem->type != XML_ELEMENT_DECL)
775 return(0);
776 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
777 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000778 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000779 if (elem->contModel != NULL) {
780 if (!xmlRegexpIsDeterminist(elem->contModel)) {
781 ctxt->valid = 0;
782 return(0);
783 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000784 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000785 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000786
787 ctxt->am = xmlNewAutomata();
788 if (ctxt->am == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000789 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
790 XML_ERR_INTERNAL_ERROR,
791 "Cannot create automata for element %s\n",
792 elem->name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000793 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000794 }
William M. Brack78637da2003-07-31 14:47:38 +0000795 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000796 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
797 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000798 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000799 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000800 char expr[5000];
801 expr[0] = 0;
802 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000803 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
804 XML_DTD_CONTENT_NOT_DETERMINIST,
805 "Content model of %s is not determinist: %s\n",
806 elem->name, BAD_CAST expr, NULL);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000807#ifdef DEBUG_REGEXP_ALGO
808 xmlRegexpPrint(stderr, elem->contModel);
809#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000810 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000811 ctxt->state = NULL;
812 xmlFreeAutomata(ctxt->am);
813 ctxt->am = NULL;
814 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000815 }
816 ctxt->state = NULL;
817 xmlFreeAutomata(ctxt->am);
818 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000819 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000820}
821
822#endif /* LIBXML_REGEXP_ENABLED */
823
Owen Taylor3473f882001-02-23 17:55:21 +0000824/****************************************************************
825 * *
826 * Util functions for data allocation/deallocation *
827 * *
828 ****************************************************************/
829
830/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000831 * xmlNewValidCtxt:
832 *
833 * Allocate a validation context structure.
834 *
835 * Returns NULL if not, otherwise the new validation context structure
836 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000837xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000838 xmlValidCtxtPtr ret;
839
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000840 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000841 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000842 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000843 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000844
845 (void) memset(ret, 0, sizeof (xmlValidCtxt));
846
847 return (ret);
848}
849
850/**
851 * xmlFreeValidCtxt:
852 * @cur: the validation context to free
853 *
854 * Free a validation context structure.
855 */
856void
857xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
858 xmlFree(cur);
859}
860
Daniel Veillard4432df22003-09-28 18:58:27 +0000861#endif /* LIBXML_VALID_ENABLED */
862
Daniel Veillarda37aab82003-06-09 09:10:36 +0000863/**
Owen Taylor3473f882001-02-23 17:55:21 +0000864 * xmlNewElementContent:
865 * @name: the subelement name or NULL
866 * @type: the type of element content decl
867 *
868 * Allocate an element content structure.
869 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000870 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000871 */
872xmlElementContentPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000873xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000874 xmlElementContentPtr ret;
875
876 switch(type) {
877 case XML_ELEMENT_CONTENT_ELEMENT:
878 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000879 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
880 "xmlNewElementContent : name == NULL !\n",
881 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000882 }
883 break;
884 case XML_ELEMENT_CONTENT_PCDATA:
885 case XML_ELEMENT_CONTENT_SEQ:
886 case XML_ELEMENT_CONTENT_OR:
887 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000888 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
889 "xmlNewElementContent : name != NULL !\n",
890 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000891 }
892 break;
893 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000894 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
895 "Internal: ELEMENT content corrupted invalid type\n",
896 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000897 return(NULL);
898 }
899 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
900 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000901 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000902 return(NULL);
903 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000904 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000905 ret->type = type;
906 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000907 if (name != NULL) {
908 xmlChar *prefix = NULL;
909 ret->name = xmlSplitQName2(name, &prefix);
910 if (ret->name == NULL)
911 ret->name = xmlStrdup(name);
912 ret->prefix = prefix;
913 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000914 ret->name = NULL;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000915 ret->prefix = NULL;
916 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000917 ret->c1 = ret->c2 = ret->parent = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000918 return(ret);
919}
920
921/**
922 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000923 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +0000924 *
925 * Build a copy of an element content description.
926 *
927 * Returns the new xmlElementContentPtr or NULL in case of error.
928 */
929xmlElementContentPtr
930xmlCopyElementContent(xmlElementContentPtr cur) {
931 xmlElementContentPtr ret;
932
933 if (cur == NULL) return(NULL);
934 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
935 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000936 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000937 return(NULL);
938 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000939 if (cur->prefix != NULL)
940 ret->prefix = xmlStrdup(cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000941 ret->ocur = cur->ocur;
942 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000943 if (ret->c1 != NULL)
944 ret->c1->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000945 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000946 if (ret->c2 != NULL)
947 ret->c2->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000948 return(ret);
949}
950
951/**
952 * xmlFreeElementContent:
953 * @cur: the element content tree to free
954 *
955 * Free an element content structure. This is a recursive call !
956 */
957void
958xmlFreeElementContent(xmlElementContentPtr cur) {
959 if (cur == NULL) return;
960 switch (cur->type) {
961 case XML_ELEMENT_CONTENT_PCDATA:
962 case XML_ELEMENT_CONTENT_ELEMENT:
963 case XML_ELEMENT_CONTENT_SEQ:
964 case XML_ELEMENT_CONTENT_OR:
965 break;
966 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000967 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
968 "Internal: ELEMENT content corrupted invalid type\n",
969 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000970 return;
971 }
972 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
973 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
974 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000975 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000976 xmlFree(cur);
977}
978
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000979#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000980/**
981 * xmlDumpElementContent:
982 * @buf: An XML buffer
983 * @content: An element table
984 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
985 *
986 * This will dump the content of the element table as an XML DTD definition
987 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000988static void
Owen Taylor3473f882001-02-23 17:55:21 +0000989xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
990 if (content == NULL) return;
991
992 if (glob) xmlBufferWriteChar(buf, "(");
993 switch (content->type) {
994 case XML_ELEMENT_CONTENT_PCDATA:
995 xmlBufferWriteChar(buf, "#PCDATA");
996 break;
997 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000998 if (content->prefix != NULL) {
999 xmlBufferWriteCHAR(buf, content->prefix);
1000 xmlBufferWriteChar(buf, ":");
1001 }
Owen Taylor3473f882001-02-23 17:55:21 +00001002 xmlBufferWriteCHAR(buf, content->name);
1003 break;
1004 case XML_ELEMENT_CONTENT_SEQ:
1005 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1006 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1007 xmlDumpElementContent(buf, content->c1, 1);
1008 else
1009 xmlDumpElementContent(buf, content->c1, 0);
1010 xmlBufferWriteChar(buf, " , ");
1011 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
1012 xmlDumpElementContent(buf, content->c2, 1);
1013 else
1014 xmlDumpElementContent(buf, content->c2, 0);
1015 break;
1016 case XML_ELEMENT_CONTENT_OR:
1017 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1018 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1019 xmlDumpElementContent(buf, content->c1, 1);
1020 else
1021 xmlDumpElementContent(buf, content->c1, 0);
1022 xmlBufferWriteChar(buf, " | ");
1023 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
1024 xmlDumpElementContent(buf, content->c2, 1);
1025 else
1026 xmlDumpElementContent(buf, content->c2, 0);
1027 break;
1028 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001029 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1030 "Internal: ELEMENT content corrupted invalid type\n",
1031 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001032 }
1033 if (glob)
1034 xmlBufferWriteChar(buf, ")");
1035 switch (content->ocur) {
1036 case XML_ELEMENT_CONTENT_ONCE:
1037 break;
1038 case XML_ELEMENT_CONTENT_OPT:
1039 xmlBufferWriteChar(buf, "?");
1040 break;
1041 case XML_ELEMENT_CONTENT_MULT:
1042 xmlBufferWriteChar(buf, "*");
1043 break;
1044 case XML_ELEMENT_CONTENT_PLUS:
1045 xmlBufferWriteChar(buf, "+");
1046 break;
1047 }
1048}
1049
1050/**
1051 * xmlSprintfElementContent:
1052 * @buf: an output buffer
1053 * @content: An element table
1054 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1055 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001056 * Deprecated, unsafe, use xmlSnprintfElementContent
1057 */
1058void
1059xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1060 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1061 int glob ATTRIBUTE_UNUSED) {
1062}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001063#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001064
1065/**
1066 * xmlSnprintfElementContent:
1067 * @buf: an output buffer
1068 * @size: the buffer size
1069 * @content: An element table
1070 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1071 *
Owen Taylor3473f882001-02-23 17:55:21 +00001072 * This will dump the content of the element content definition
1073 * Intended just for the debug routine
1074 */
1075void
Daniel Veillardd3d06722001-08-15 12:06:36 +00001076xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int glob) {
1077 int len;
1078
Owen Taylor3473f882001-02-23 17:55:21 +00001079 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001080 len = strlen(buf);
1081 if (size - len < 50) {
1082 if ((size - len > 4) && (buf[len - 1] != '.'))
1083 strcat(buf, " ...");
1084 return;
1085 }
Owen Taylor3473f882001-02-23 17:55:21 +00001086 if (glob) strcat(buf, "(");
1087 switch (content->type) {
1088 case XML_ELEMENT_CONTENT_PCDATA:
1089 strcat(buf, "#PCDATA");
1090 break;
1091 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001092 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001093 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001094 strcat(buf, " ...");
1095 return;
1096 }
1097 strcat(buf, (char *) content->prefix);
1098 strcat(buf, ":");
1099 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001100 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001101 strcat(buf, " ...");
1102 return;
1103 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001104 if (content->name != NULL)
1105 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001106 break;
1107 case XML_ELEMENT_CONTENT_SEQ:
1108 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1109 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001110 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001111 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001112 xmlSnprintfElementContent(buf, size, content->c1, 0);
1113 len = strlen(buf);
1114 if (size - len < 50) {
1115 if ((size - len > 4) && (buf[len - 1] != '.'))
1116 strcat(buf, " ...");
1117 return;
1118 }
Owen Taylor3473f882001-02-23 17:55:21 +00001119 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001120 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1121 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1122 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001123 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001124 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001125 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001126 break;
1127 case XML_ELEMENT_CONTENT_OR:
1128 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1129 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001130 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001131 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001132 xmlSnprintfElementContent(buf, size, content->c1, 0);
1133 len = strlen(buf);
1134 if (size - len < 50) {
1135 if ((size - len > 4) && (buf[len - 1] != '.'))
1136 strcat(buf, " ...");
1137 return;
1138 }
Owen Taylor3473f882001-02-23 17:55:21 +00001139 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001140 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1141 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1142 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001143 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001144 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001145 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001146 break;
1147 }
1148 if (glob)
1149 strcat(buf, ")");
1150 switch (content->ocur) {
1151 case XML_ELEMENT_CONTENT_ONCE:
1152 break;
1153 case XML_ELEMENT_CONTENT_OPT:
1154 strcat(buf, "?");
1155 break;
1156 case XML_ELEMENT_CONTENT_MULT:
1157 strcat(buf, "*");
1158 break;
1159 case XML_ELEMENT_CONTENT_PLUS:
1160 strcat(buf, "+");
1161 break;
1162 }
1163}
1164
1165/****************************************************************
1166 * *
1167 * Registration of DTD declarations *
1168 * *
1169 ****************************************************************/
1170
1171/**
1172 * xmlCreateElementTable:
1173 *
1174 * create and initialize an empty element hash table.
1175 *
1176 * Returns the xmlElementTablePtr just created or NULL in case of error.
1177 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001178static xmlElementTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001179xmlCreateElementTable(void) {
1180 return(xmlHashCreate(0));
1181}
1182
1183/**
1184 * xmlFreeElement:
1185 * @elem: An element
1186 *
1187 * Deallocate the memory used by an element definition
1188 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001189static void
Owen Taylor3473f882001-02-23 17:55:21 +00001190xmlFreeElement(xmlElementPtr elem) {
1191 if (elem == NULL) return;
1192 xmlUnlinkNode((xmlNodePtr) elem);
1193 xmlFreeElementContent(elem->content);
1194 if (elem->name != NULL)
1195 xmlFree((xmlChar *) elem->name);
1196 if (elem->prefix != NULL)
1197 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001198#ifdef LIBXML_REGEXP_ENABLED
1199 if (elem->contModel != NULL)
1200 xmlRegFreeRegexp(elem->contModel);
1201#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001202 xmlFree(elem);
1203}
1204
1205
1206/**
1207 * xmlAddElementDecl:
1208 * @ctxt: the validation context
1209 * @dtd: pointer to the DTD
1210 * @name: the entity name
1211 * @type: the element type
1212 * @content: the element content tree or NULL
1213 *
1214 * Register a new element declaration
1215 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001216 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001217 */
1218xmlElementPtr
William M. Brackedb65a72004-02-06 07:36:04 +00001219xmlAddElementDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001220 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001221 xmlElementTypeVal type,
1222 xmlElementContentPtr content) {
1223 xmlElementPtr ret;
1224 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001225 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001226 xmlChar *ns, *uqname;
1227
1228 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001229 return(NULL);
1230 }
1231 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001232 return(NULL);
1233 }
1234 switch (type) {
1235 case XML_ELEMENT_TYPE_EMPTY:
1236 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001237 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1238 "xmlAddElementDecl: content != NULL for EMPTY\n",
1239 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001240 return(NULL);
1241 }
1242 break;
1243 case XML_ELEMENT_TYPE_ANY:
1244 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001245 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1246 "xmlAddElementDecl: content != NULL for ANY\n",
1247 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001248 return(NULL);
1249 }
1250 break;
1251 case XML_ELEMENT_TYPE_MIXED:
1252 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001253 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1254 "xmlAddElementDecl: content == NULL for MIXED\n",
1255 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001256 return(NULL);
1257 }
1258 break;
1259 case XML_ELEMENT_TYPE_ELEMENT:
1260 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001261 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1262 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1263 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001264 return(NULL);
1265 }
1266 break;
1267 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001268 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1269 "Internal: ELEMENT decl corrupted invalid type\n",
1270 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001271 return(NULL);
1272 }
1273
1274 /*
1275 * check if name is a QName
1276 */
1277 uqname = xmlSplitQName2(name, &ns);
1278 if (uqname != NULL)
1279 name = uqname;
1280
1281 /*
1282 * Create the Element table if needed.
1283 */
1284 table = (xmlElementTablePtr) dtd->elements;
1285 if (table == NULL) {
1286 table = xmlCreateElementTable();
1287 dtd->elements = (void *) table;
1288 }
1289 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001290 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001291 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001292 if (uqname != NULL)
1293 xmlFree(uqname);
1294 if (ns != NULL)
1295 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001296 return(NULL);
1297 }
1298
Daniel Veillarda10efa82001-04-18 13:09:01 +00001299 /*
1300 * lookup old attributes inserted on an undefined element in the
1301 * internal subset.
1302 */
1303 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1304 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1305 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1306 oldAttributes = ret->attributes;
1307 ret->attributes = NULL;
1308 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1309 xmlFreeElement(ret);
1310 }
Owen Taylor3473f882001-02-23 17:55:21 +00001311 }
Owen Taylor3473f882001-02-23 17:55:21 +00001312
1313 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001314 * The element may already be present if one of its attribute
1315 * was registered first
1316 */
1317 ret = xmlHashLookup2(table, name, ns);
1318 if (ret != NULL) {
1319 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001320#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001321 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001322 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001323 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001324 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1325 "Redefinition of element %s\n",
1326 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001327#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001328 if (uqname != NULL)
1329 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001330 if (ns != NULL)
1331 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001332 return(NULL);
1333 }
1334 } else {
1335 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1336 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001337 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001338 if (uqname != NULL)
1339 xmlFree(uqname);
1340 if (ns != NULL)
1341 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001342 return(NULL);
1343 }
1344 memset(ret, 0, sizeof(xmlElement));
1345 ret->type = XML_ELEMENT_DECL;
1346
1347 /*
1348 * fill the structure.
1349 */
1350 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001351 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001352 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001353 if (uqname != NULL)
1354 xmlFree(uqname);
1355 if (ns != NULL)
1356 xmlFree(ns);
1357 xmlFree(ret);
1358 return(NULL);
1359 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001360 ret->prefix = ns;
1361
1362 /*
1363 * Validity Check:
1364 * Insertion must not fail
1365 */
1366 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001367#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001368 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001369 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001370 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001371 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1372 "Redefinition of element %s\n",
1373 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001374#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001375 xmlFreeElement(ret);
1376 if (uqname != NULL)
1377 xmlFree(uqname);
1378 return(NULL);
1379 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001380 /*
1381 * For new element, may have attributes from earlier
1382 * definition in internal subset
1383 */
1384 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001385 }
1386
1387 /*
1388 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001389 */
1390 ret->etype = type;
Owen Taylor3473f882001-02-23 17:55:21 +00001391 ret->content = xmlCopyElementContent(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001392
1393 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001394 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001395 */
1396 ret->parent = dtd;
1397 ret->doc = dtd->doc;
1398 if (dtd->last == NULL) {
1399 dtd->children = dtd->last = (xmlNodePtr) ret;
1400 } else {
1401 dtd->last->next = (xmlNodePtr) ret;
1402 ret->prev = dtd->last;
1403 dtd->last = (xmlNodePtr) ret;
1404 }
1405 if (uqname != NULL)
1406 xmlFree(uqname);
1407 return(ret);
1408}
1409
1410/**
1411 * xmlFreeElementTable:
1412 * @table: An element table
1413 *
1414 * Deallocate the memory used by an element hash table.
1415 */
1416void
1417xmlFreeElementTable(xmlElementTablePtr table) {
1418 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1419}
1420
Daniel Veillard652327a2003-09-29 18:02:38 +00001421#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001422/**
1423 * xmlCopyElement:
1424 * @elem: An element
1425 *
1426 * Build a copy of an element.
1427 *
1428 * Returns the new xmlElementPtr or NULL in case of error.
1429 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001430static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001431xmlCopyElement(xmlElementPtr elem) {
1432 xmlElementPtr cur;
1433
1434 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1435 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001436 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001437 return(NULL);
1438 }
1439 memset(cur, 0, sizeof(xmlElement));
1440 cur->type = XML_ELEMENT_DECL;
1441 cur->etype = elem->etype;
1442 if (elem->name != NULL)
1443 cur->name = xmlStrdup(elem->name);
1444 else
1445 cur->name = NULL;
1446 if (elem->prefix != NULL)
1447 cur->prefix = xmlStrdup(elem->prefix);
1448 else
1449 cur->prefix = NULL;
1450 cur->content = xmlCopyElementContent(elem->content);
1451 /* TODO : rebuild the attribute list on the copy */
1452 cur->attributes = NULL;
1453 return(cur);
1454}
1455
1456/**
1457 * xmlCopyElementTable:
1458 * @table: An element table
1459 *
1460 * Build a copy of an element table.
1461 *
1462 * Returns the new xmlElementTablePtr or NULL in case of error.
1463 */
1464xmlElementTablePtr
1465xmlCopyElementTable(xmlElementTablePtr table) {
1466 return((xmlElementTablePtr) xmlHashCopy(table,
1467 (xmlHashCopier) xmlCopyElement));
1468}
Daniel Veillard652327a2003-09-29 18:02:38 +00001469#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001470
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001471#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001472/**
1473 * xmlDumpElementDecl:
1474 * @buf: the XML buffer output
1475 * @elem: An element table
1476 *
1477 * This will dump the content of the element declaration as an XML
1478 * DTD definition
1479 */
1480void
1481xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1482 switch (elem->etype) {
1483 case XML_ELEMENT_TYPE_EMPTY:
1484 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001485 if (elem->prefix != NULL) {
1486 xmlBufferWriteCHAR(buf, elem->prefix);
1487 xmlBufferWriteChar(buf, ":");
1488 }
Owen Taylor3473f882001-02-23 17:55:21 +00001489 xmlBufferWriteCHAR(buf, elem->name);
1490 xmlBufferWriteChar(buf, " EMPTY>\n");
1491 break;
1492 case XML_ELEMENT_TYPE_ANY:
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, " ANY>\n");
1500 break;
1501 case XML_ELEMENT_TYPE_MIXED:
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, " ");
1509 xmlDumpElementContent(buf, elem->content, 1);
1510 xmlBufferWriteChar(buf, ">\n");
1511 break;
1512 case XML_ELEMENT_TYPE_ELEMENT:
1513 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001514 if (elem->prefix != NULL) {
1515 xmlBufferWriteCHAR(buf, elem->prefix);
1516 xmlBufferWriteChar(buf, ":");
1517 }
Owen Taylor3473f882001-02-23 17:55:21 +00001518 xmlBufferWriteCHAR(buf, elem->name);
1519 xmlBufferWriteChar(buf, " ");
1520 xmlDumpElementContent(buf, elem->content, 1);
1521 xmlBufferWriteChar(buf, ">\n");
1522 break;
1523 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001524 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1525 "Internal: ELEMENT struct corrupted invalid type\n",
1526 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001527 }
1528}
1529
1530/**
William M. Brack9e660592003-10-20 14:56:06 +00001531 * xmlDumpElementDeclScan:
1532 * @elem: An element table
1533 * @buf: the XML buffer output
1534 *
1535 * This routine is used by the hash scan function. It just reverses
1536 * the arguments.
1537 */
1538static void
1539xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1540 xmlDumpElementDecl(buf, elem);
1541}
1542
1543/**
Owen Taylor3473f882001-02-23 17:55:21 +00001544 * xmlDumpElementTable:
1545 * @buf: the XML buffer output
1546 * @table: An element table
1547 *
1548 * This will dump the content of the element table as an XML DTD definition
1549 */
1550void
1551xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00001552 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001553}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001554#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001555
1556/**
1557 * xmlCreateEnumeration:
1558 * @name: the enumeration name or NULL
1559 *
1560 * create and initialize an enumeration attribute node.
1561 *
1562 * Returns the xmlEnumerationPtr just created or NULL in case
1563 * of error.
1564 */
1565xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001566xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001567 xmlEnumerationPtr ret;
1568
1569 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1570 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001571 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001572 return(NULL);
1573 }
1574 memset(ret, 0, sizeof(xmlEnumeration));
1575
1576 if (name != NULL)
1577 ret->name = xmlStrdup(name);
1578 return(ret);
1579}
1580
1581/**
1582 * xmlFreeEnumeration:
1583 * @cur: the tree to free.
1584 *
1585 * free an enumeration attribute node (recursive).
1586 */
1587void
1588xmlFreeEnumeration(xmlEnumerationPtr cur) {
1589 if (cur == NULL) return;
1590
1591 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1592
1593 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001594 xmlFree(cur);
1595}
1596
Daniel Veillard652327a2003-09-29 18:02:38 +00001597#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001598/**
1599 * xmlCopyEnumeration:
1600 * @cur: the tree to copy.
1601 *
1602 * Copy an enumeration attribute node (recursive).
1603 *
1604 * Returns the xmlEnumerationPtr just created or NULL in case
1605 * of error.
1606 */
1607xmlEnumerationPtr
1608xmlCopyEnumeration(xmlEnumerationPtr cur) {
1609 xmlEnumerationPtr ret;
1610
1611 if (cur == NULL) return(NULL);
1612 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1613
1614 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1615 else ret->next = NULL;
1616
1617 return(ret);
1618}
Daniel Veillard652327a2003-09-29 18:02:38 +00001619#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001620
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001621#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001622/**
1623 * xmlDumpEnumeration:
1624 * @buf: the XML buffer output
1625 * @enum: An enumeration
1626 *
1627 * This will dump the content of the enumeration
1628 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001629static void
Owen Taylor3473f882001-02-23 17:55:21 +00001630xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1631 if (cur == NULL) return;
1632
1633 xmlBufferWriteCHAR(buf, cur->name);
1634 if (cur->next == NULL)
1635 xmlBufferWriteChar(buf, ")");
1636 else {
1637 xmlBufferWriteChar(buf, " | ");
1638 xmlDumpEnumeration(buf, cur->next);
1639 }
1640}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001641#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001642
1643/**
1644 * xmlCreateAttributeTable:
1645 *
1646 * create and initialize an empty attribute hash table.
1647 *
1648 * Returns the xmlAttributeTablePtr just created or NULL in case
1649 * of error.
1650 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001651static xmlAttributeTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001652xmlCreateAttributeTable(void) {
1653 return(xmlHashCreate(0));
1654}
1655
Daniel Veillard4432df22003-09-28 18:58:27 +00001656#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001657/**
1658 * xmlScanAttributeDeclCallback:
1659 * @attr: the attribute decl
1660 * @list: the list to update
1661 *
1662 * Callback called by xmlScanAttributeDecl when a new attribute
1663 * has to be entered in the list.
1664 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001665static void
Owen Taylor3473f882001-02-23 17:55:21 +00001666xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001667 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001668 attr->nexth = *list;
1669 *list = attr;
1670}
1671
1672/**
1673 * xmlScanAttributeDecl:
1674 * @dtd: pointer to the DTD
1675 * @elem: the element name
1676 *
1677 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001678 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001679 *
1680 * Returns the pointer to the first attribute decl in the chain,
1681 * possibly NULL.
1682 */
1683xmlAttributePtr
1684xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1685 xmlAttributePtr ret = NULL;
1686 xmlAttributeTablePtr table;
1687
1688 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001689 return(NULL);
1690 }
1691 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001692 return(NULL);
1693 }
1694 table = (xmlAttributeTablePtr) dtd->attributes;
1695 if (table == NULL)
1696 return(NULL);
1697
1698 /* WRONG !!! */
1699 xmlHashScan3(table, NULL, NULL, elem,
1700 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1701 return(ret);
1702}
1703
1704/**
1705 * xmlScanIDAttributeDecl:
1706 * @ctxt: the validation context
1707 * @elem: the element name
1708 *
1709 * Verify that the element don't have too many ID attributes
1710 * declared.
1711 *
1712 * Returns the number of ID attributes found.
1713 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001714static int
Owen Taylor3473f882001-02-23 17:55:21 +00001715xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1716 xmlAttributePtr cur;
1717 int ret = 0;
1718
1719 if (elem == NULL) return(0);
1720 cur = elem->attributes;
1721 while (cur != NULL) {
1722 if (cur->atype == XML_ATTRIBUTE_ID) {
1723 ret ++;
1724 if (ret > 1)
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001725 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001726 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001727 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001728 }
1729 cur = cur->nexth;
1730 }
1731 return(ret);
1732}
Daniel Veillard4432df22003-09-28 18:58:27 +00001733#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001734
1735/**
1736 * xmlFreeAttribute:
1737 * @elem: An attribute
1738 *
1739 * Deallocate the memory used by an attribute definition
1740 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001741static void
Owen Taylor3473f882001-02-23 17:55:21 +00001742xmlFreeAttribute(xmlAttributePtr attr) {
1743 if (attr == NULL) return;
1744 xmlUnlinkNode((xmlNodePtr) attr);
1745 if (attr->tree != NULL)
1746 xmlFreeEnumeration(attr->tree);
1747 if (attr->elem != NULL)
1748 xmlFree((xmlChar *) attr->elem);
1749 if (attr->name != NULL)
1750 xmlFree((xmlChar *) attr->name);
1751 if (attr->defaultValue != NULL)
1752 xmlFree((xmlChar *) attr->defaultValue);
1753 if (attr->prefix != NULL)
1754 xmlFree((xmlChar *) attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001755 xmlFree(attr);
1756}
1757
1758
1759/**
1760 * xmlAddAttributeDecl:
1761 * @ctxt: the validation context
1762 * @dtd: pointer to the DTD
1763 * @elem: the element name
1764 * @name: the attribute name
1765 * @ns: the attribute namespace prefix
1766 * @type: the attribute type
1767 * @def: the attribute default type
1768 * @defaultValue: the attribute default value
1769 * @tree: if it's an enumeration, the associated list
1770 *
1771 * Register a new attribute declaration
1772 * Note that @tree becomes the ownership of the DTD
1773 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001774 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001775 */
1776xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001777xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001778 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001779 const xmlChar *name, const xmlChar *ns,
1780 xmlAttributeType type, xmlAttributeDefault def,
1781 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1782 xmlAttributePtr ret;
1783 xmlAttributeTablePtr table;
1784 xmlElementPtr elemDef;
1785
1786 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001787 xmlFreeEnumeration(tree);
1788 return(NULL);
1789 }
1790 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001791 xmlFreeEnumeration(tree);
1792 return(NULL);
1793 }
1794 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001795 xmlFreeEnumeration(tree);
1796 return(NULL);
1797 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001798
Daniel Veillard4432df22003-09-28 18:58:27 +00001799#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001800 /*
1801 * Check the type and possibly the default value.
1802 */
1803 switch (type) {
1804 case XML_ATTRIBUTE_CDATA:
1805 break;
1806 case XML_ATTRIBUTE_ID:
1807 break;
1808 case XML_ATTRIBUTE_IDREF:
1809 break;
1810 case XML_ATTRIBUTE_IDREFS:
1811 break;
1812 case XML_ATTRIBUTE_ENTITY:
1813 break;
1814 case XML_ATTRIBUTE_ENTITIES:
1815 break;
1816 case XML_ATTRIBUTE_NMTOKEN:
1817 break;
1818 case XML_ATTRIBUTE_NMTOKENS:
1819 break;
1820 case XML_ATTRIBUTE_ENUMERATION:
1821 break;
1822 case XML_ATTRIBUTE_NOTATION:
1823 break;
1824 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001825 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1826 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1827 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001828 xmlFreeEnumeration(tree);
1829 return(NULL);
1830 }
1831 if ((defaultValue != NULL) &&
1832 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001833 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1834 "Attribute %s of %s: invalid default value\n",
1835 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00001836 defaultValue = NULL;
Daniel Veillardd01fd3e2002-02-18 22:27:47 +00001837 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001838 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001839#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001840
1841 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001842 * Check first that an attribute defined in the external subset wasn't
1843 * already defined in the internal subset
1844 */
1845 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1846 (dtd->doc->intSubset != NULL) &&
1847 (dtd->doc->intSubset->attributes != NULL)) {
1848 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1849 if (ret != NULL)
1850 return(NULL);
1851 }
1852
1853 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001854 * Create the Attribute table if needed.
1855 */
1856 table = (xmlAttributeTablePtr) dtd->attributes;
1857 if (table == NULL) {
1858 table = xmlCreateAttributeTable();
1859 dtd->attributes = (void *) table;
1860 }
1861 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001862 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001863 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001864 return(NULL);
1865 }
1866
1867
1868 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1869 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001870 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001871 return(NULL);
1872 }
1873 memset(ret, 0, sizeof(xmlAttribute));
1874 ret->type = XML_ATTRIBUTE_DECL;
1875
1876 /*
1877 * fill the structure.
1878 */
1879 ret->atype = type;
1880 ret->name = xmlStrdup(name);
1881 ret->prefix = xmlStrdup(ns);
1882 ret->elem = xmlStrdup(elem);
1883 ret->def = def;
1884 ret->tree = tree;
1885 if (defaultValue != NULL)
1886 ret->defaultValue = xmlStrdup(defaultValue);
1887
1888 /*
1889 * Validity Check:
1890 * Search the DTD for previous declarations of the ATTLIST
1891 */
1892 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001893#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001894 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001895 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00001896 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001897 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00001898 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001899 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001900#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001901 xmlFreeAttribute(ret);
1902 return(NULL);
1903 }
1904
1905 /*
1906 * Validity Check:
1907 * Multiple ID per element
1908 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001909 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001910 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00001911
Daniel Veillard4432df22003-09-28 18:58:27 +00001912#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001913 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00001914 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001915 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00001916 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001917 elem, name, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00001918 ctxt->valid = 0;
1919 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001920#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00001921
Daniel Veillard48da9102001-08-07 01:10:10 +00001922 /*
1923 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001924 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00001925 */
1926 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1927 ((ret->prefix != NULL &&
1928 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1929 ret->nexth = elemDef->attributes;
1930 elemDef->attributes = ret;
1931 } else {
1932 xmlAttributePtr tmp = elemDef->attributes;
1933
1934 while ((tmp != NULL) &&
1935 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1936 ((ret->prefix != NULL &&
1937 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1938 if (tmp->nexth == NULL)
1939 break;
1940 tmp = tmp->nexth;
1941 }
1942 if (tmp != NULL) {
1943 ret->nexth = tmp->nexth;
1944 tmp->nexth = ret;
1945 } else {
1946 ret->nexth = elemDef->attributes;
1947 elemDef->attributes = ret;
1948 }
1949 }
Owen Taylor3473f882001-02-23 17:55:21 +00001950 }
1951
1952 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001953 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001954 */
1955 ret->parent = dtd;
1956 ret->doc = dtd->doc;
1957 if (dtd->last == NULL) {
1958 dtd->children = dtd->last = (xmlNodePtr) ret;
1959 } else {
1960 dtd->last->next = (xmlNodePtr) ret;
1961 ret->prev = dtd->last;
1962 dtd->last = (xmlNodePtr) ret;
1963 }
1964 return(ret);
1965}
1966
1967/**
1968 * xmlFreeAttributeTable:
1969 * @table: An attribute table
1970 *
1971 * Deallocate the memory used by an entities hash table.
1972 */
1973void
1974xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1975 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
1976}
1977
Daniel Veillard652327a2003-09-29 18:02:38 +00001978#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001979/**
1980 * xmlCopyAttribute:
1981 * @attr: An attribute
1982 *
1983 * Build a copy of an attribute.
1984 *
1985 * Returns the new xmlAttributePtr or NULL in case of error.
1986 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001987static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001988xmlCopyAttribute(xmlAttributePtr attr) {
1989 xmlAttributePtr cur;
1990
1991 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1992 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001993 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001994 return(NULL);
1995 }
1996 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00001997 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00001998 cur->atype = attr->atype;
1999 cur->def = attr->def;
2000 cur->tree = xmlCopyEnumeration(attr->tree);
2001 if (attr->elem != NULL)
2002 cur->elem = xmlStrdup(attr->elem);
2003 if (attr->name != NULL)
2004 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002005 if (attr->prefix != NULL)
2006 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002007 if (attr->defaultValue != NULL)
2008 cur->defaultValue = xmlStrdup(attr->defaultValue);
2009 return(cur);
2010}
2011
2012/**
2013 * xmlCopyAttributeTable:
2014 * @table: An attribute table
2015 *
2016 * Build a copy of an attribute table.
2017 *
2018 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2019 */
2020xmlAttributeTablePtr
2021xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2022 return((xmlAttributeTablePtr) xmlHashCopy(table,
2023 (xmlHashCopier) xmlCopyAttribute));
2024}
Daniel Veillard652327a2003-09-29 18:02:38 +00002025#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002026
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002027#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002028/**
2029 * xmlDumpAttributeDecl:
2030 * @buf: the XML buffer output
2031 * @attr: An attribute declaration
2032 *
2033 * This will dump the content of the attribute declaration as an XML
2034 * DTD definition
2035 */
2036void
2037xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2038 xmlBufferWriteChar(buf, "<!ATTLIST ");
2039 xmlBufferWriteCHAR(buf, attr->elem);
2040 xmlBufferWriteChar(buf, " ");
2041 if (attr->prefix != NULL) {
2042 xmlBufferWriteCHAR(buf, attr->prefix);
2043 xmlBufferWriteChar(buf, ":");
2044 }
2045 xmlBufferWriteCHAR(buf, attr->name);
2046 switch (attr->atype) {
2047 case XML_ATTRIBUTE_CDATA:
2048 xmlBufferWriteChar(buf, " CDATA");
2049 break;
2050 case XML_ATTRIBUTE_ID:
2051 xmlBufferWriteChar(buf, " ID");
2052 break;
2053 case XML_ATTRIBUTE_IDREF:
2054 xmlBufferWriteChar(buf, " IDREF");
2055 break;
2056 case XML_ATTRIBUTE_IDREFS:
2057 xmlBufferWriteChar(buf, " IDREFS");
2058 break;
2059 case XML_ATTRIBUTE_ENTITY:
2060 xmlBufferWriteChar(buf, " ENTITY");
2061 break;
2062 case XML_ATTRIBUTE_ENTITIES:
2063 xmlBufferWriteChar(buf, " ENTITIES");
2064 break;
2065 case XML_ATTRIBUTE_NMTOKEN:
2066 xmlBufferWriteChar(buf, " NMTOKEN");
2067 break;
2068 case XML_ATTRIBUTE_NMTOKENS:
2069 xmlBufferWriteChar(buf, " NMTOKENS");
2070 break;
2071 case XML_ATTRIBUTE_ENUMERATION:
2072 xmlBufferWriteChar(buf, " (");
2073 xmlDumpEnumeration(buf, attr->tree);
2074 break;
2075 case XML_ATTRIBUTE_NOTATION:
2076 xmlBufferWriteChar(buf, " NOTATION (");
2077 xmlDumpEnumeration(buf, attr->tree);
2078 break;
2079 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002080 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2081 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2082 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002083 }
2084 switch (attr->def) {
2085 case XML_ATTRIBUTE_NONE:
2086 break;
2087 case XML_ATTRIBUTE_REQUIRED:
2088 xmlBufferWriteChar(buf, " #REQUIRED");
2089 break;
2090 case XML_ATTRIBUTE_IMPLIED:
2091 xmlBufferWriteChar(buf, " #IMPLIED");
2092 break;
2093 case XML_ATTRIBUTE_FIXED:
2094 xmlBufferWriteChar(buf, " #FIXED");
2095 break;
2096 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002097 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2098 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2099 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002100 }
2101 if (attr->defaultValue != NULL) {
2102 xmlBufferWriteChar(buf, " ");
2103 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2104 }
2105 xmlBufferWriteChar(buf, ">\n");
2106}
2107
2108/**
William M. Brack9e660592003-10-20 14:56:06 +00002109 * xmlDumpAttributeDeclScan:
2110 * @attr: An attribute declaration
2111 * @buf: the XML buffer output
2112 *
2113 * This is used with the hash scan function - just reverses arguments
2114 */
2115static void
2116xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2117 xmlDumpAttributeDecl(buf, attr);
2118}
2119
2120/**
Owen Taylor3473f882001-02-23 17:55:21 +00002121 * xmlDumpAttributeTable:
2122 * @buf: the XML buffer output
2123 * @table: An attribute table
2124 *
2125 * This will dump the content of the attribute table as an XML DTD definition
2126 */
2127void
2128xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002129 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002130}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002131#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002132
2133/************************************************************************
2134 * *
2135 * NOTATIONs *
2136 * *
2137 ************************************************************************/
2138/**
2139 * xmlCreateNotationTable:
2140 *
2141 * create and initialize an empty notation hash table.
2142 *
2143 * Returns the xmlNotationTablePtr just created or NULL in case
2144 * of error.
2145 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002146static xmlNotationTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002147xmlCreateNotationTable(void) {
2148 return(xmlHashCreate(0));
2149}
2150
2151/**
2152 * xmlFreeNotation:
2153 * @not: A notation
2154 *
2155 * Deallocate the memory used by an notation definition
2156 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002157static void
Owen Taylor3473f882001-02-23 17:55:21 +00002158xmlFreeNotation(xmlNotationPtr nota) {
2159 if (nota == NULL) return;
2160 if (nota->name != NULL)
2161 xmlFree((xmlChar *) nota->name);
2162 if (nota->PublicID != NULL)
2163 xmlFree((xmlChar *) nota->PublicID);
2164 if (nota->SystemID != NULL)
2165 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002166 xmlFree(nota);
2167}
2168
2169
2170/**
2171 * xmlAddNotationDecl:
2172 * @dtd: pointer to the DTD
2173 * @ctxt: the validation context
2174 * @name: the entity name
2175 * @PublicID: the public identifier or NULL
2176 * @SystemID: the system identifier or NULL
2177 *
2178 * Register a new notation declaration
2179 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002180 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002181 */
2182xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002183xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002184 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002185 const xmlChar *PublicID, const xmlChar *SystemID) {
2186 xmlNotationPtr ret;
2187 xmlNotationTablePtr table;
2188
2189 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002190 return(NULL);
2191 }
2192 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002193 return(NULL);
2194 }
2195 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002196 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002197 }
2198
2199 /*
2200 * Create the Notation table if needed.
2201 */
2202 table = (xmlNotationTablePtr) dtd->notations;
2203 if (table == NULL)
2204 dtd->notations = table = xmlCreateNotationTable();
2205 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002206 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002207 "xmlAddNotationDecl: Table creation failed!\n");
2208 return(NULL);
2209 }
2210
2211 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2212 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002213 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002214 return(NULL);
2215 }
2216 memset(ret, 0, sizeof(xmlNotation));
2217
2218 /*
2219 * fill the structure.
2220 */
2221 ret->name = xmlStrdup(name);
2222 if (SystemID != NULL)
2223 ret->SystemID = xmlStrdup(SystemID);
2224 if (PublicID != NULL)
2225 ret->PublicID = xmlStrdup(PublicID);
2226
2227 /*
2228 * Validity Check:
2229 * Check the DTD for previous declarations of the ATTLIST
2230 */
2231 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002232#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002233 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2234 "xmlAddNotationDecl: %s already defined\n",
2235 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002236#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002237 xmlFreeNotation(ret);
2238 return(NULL);
2239 }
2240 return(ret);
2241}
2242
2243/**
2244 * xmlFreeNotationTable:
2245 * @table: An notation table
2246 *
2247 * Deallocate the memory used by an entities hash table.
2248 */
2249void
2250xmlFreeNotationTable(xmlNotationTablePtr table) {
2251 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2252}
2253
Daniel Veillard652327a2003-09-29 18:02:38 +00002254#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002255/**
2256 * xmlCopyNotation:
2257 * @nota: A notation
2258 *
2259 * Build a copy of a notation.
2260 *
2261 * Returns the new xmlNotationPtr or NULL in case of error.
2262 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002263static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002264xmlCopyNotation(xmlNotationPtr nota) {
2265 xmlNotationPtr cur;
2266
2267 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2268 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002269 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002270 return(NULL);
2271 }
2272 if (nota->name != NULL)
2273 cur->name = xmlStrdup(nota->name);
2274 else
2275 cur->name = NULL;
2276 if (nota->PublicID != NULL)
2277 cur->PublicID = xmlStrdup(nota->PublicID);
2278 else
2279 cur->PublicID = NULL;
2280 if (nota->SystemID != NULL)
2281 cur->SystemID = xmlStrdup(nota->SystemID);
2282 else
2283 cur->SystemID = NULL;
2284 return(cur);
2285}
2286
2287/**
2288 * xmlCopyNotationTable:
2289 * @table: A notation table
2290 *
2291 * Build a copy of a notation table.
2292 *
2293 * Returns the new xmlNotationTablePtr or NULL in case of error.
2294 */
2295xmlNotationTablePtr
2296xmlCopyNotationTable(xmlNotationTablePtr table) {
2297 return((xmlNotationTablePtr) xmlHashCopy(table,
2298 (xmlHashCopier) xmlCopyNotation));
2299}
Daniel Veillard652327a2003-09-29 18:02:38 +00002300#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002301
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002302#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002303/**
2304 * xmlDumpNotationDecl:
2305 * @buf: the XML buffer output
2306 * @nota: A notation declaration
2307 *
2308 * This will dump the content the notation declaration as an XML DTD definition
2309 */
2310void
2311xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2312 xmlBufferWriteChar(buf, "<!NOTATION ");
2313 xmlBufferWriteCHAR(buf, nota->name);
2314 if (nota->PublicID != NULL) {
2315 xmlBufferWriteChar(buf, " PUBLIC ");
2316 xmlBufferWriteQuotedString(buf, nota->PublicID);
2317 if (nota->SystemID != NULL) {
2318 xmlBufferWriteChar(buf, " ");
2319 xmlBufferWriteCHAR(buf, nota->SystemID);
2320 }
2321 } else {
2322 xmlBufferWriteChar(buf, " SYSTEM ");
2323 xmlBufferWriteCHAR(buf, nota->SystemID);
2324 }
2325 xmlBufferWriteChar(buf, " >\n");
2326}
2327
2328/**
William M. Brack9e660592003-10-20 14:56:06 +00002329 * xmlDumpNotationDeclScan:
2330 * @nota: A notation declaration
2331 * @buf: the XML buffer output
2332 *
2333 * This is called with the hash scan function, and just reverses args
2334 */
2335static void
2336xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2337 xmlDumpNotationDecl(buf, nota);
2338}
2339
2340/**
Owen Taylor3473f882001-02-23 17:55:21 +00002341 * xmlDumpNotationTable:
2342 * @buf: the XML buffer output
2343 * @table: A notation table
2344 *
2345 * This will dump the content of the notation table as an XML DTD definition
2346 */
2347void
2348xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002349 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002350}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002351#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002352
2353/************************************************************************
2354 * *
2355 * IDs *
2356 * *
2357 ************************************************************************/
2358/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002359 * DICT_FREE:
2360 * @str: a string
2361 *
2362 * Free a string if it is not owned by the "dict" dictionnary in the
2363 * current scope
2364 */
2365#define DICT_FREE(str) \
2366 if ((str) && ((!dict) || \
2367 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2368 xmlFree((char *)(str));
2369
2370/**
Owen Taylor3473f882001-02-23 17:55:21 +00002371 * xmlCreateIDTable:
2372 *
2373 * create and initialize an empty id hash table.
2374 *
2375 * Returns the xmlIDTablePtr just created or NULL in case
2376 * of error.
2377 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002378static xmlIDTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002379xmlCreateIDTable(void) {
2380 return(xmlHashCreate(0));
2381}
2382
2383/**
2384 * xmlFreeID:
2385 * @not: A id
2386 *
2387 * Deallocate the memory used by an id definition
2388 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002389static void
Owen Taylor3473f882001-02-23 17:55:21 +00002390xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002391 xmlDictPtr dict = NULL;
2392
Owen Taylor3473f882001-02-23 17:55:21 +00002393 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002394
2395 if (id->doc != NULL)
2396 dict = id->doc->dict;
2397
Owen Taylor3473f882001-02-23 17:55:21 +00002398 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002399 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002400 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002401 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002402 xmlFree(id);
2403}
2404
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002405
Owen Taylor3473f882001-02-23 17:55:21 +00002406/**
2407 * xmlAddID:
2408 * @ctxt: the validation context
2409 * @doc: pointer to the document
2410 * @value: the value name
2411 * @attr: the attribute holding the ID
2412 *
2413 * Register a new id declaration
2414 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002415 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002416 */
2417xmlIDPtr
2418xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2419 xmlAttrPtr attr) {
2420 xmlIDPtr ret;
2421 xmlIDTablePtr table;
2422
2423 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002424 return(NULL);
2425 }
2426 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002427 return(NULL);
2428 }
2429 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002430 return(NULL);
2431 }
2432
2433 /*
2434 * Create the ID table if needed.
2435 */
2436 table = (xmlIDTablePtr) doc->ids;
2437 if (table == NULL)
2438 doc->ids = table = xmlCreateIDTable();
2439 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002440 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002441 "xmlAddID: Table creation failed!\n");
2442 return(NULL);
2443 }
2444
2445 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2446 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002447 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002448 return(NULL);
2449 }
2450
2451 /*
2452 * fill the structure.
2453 */
2454 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002455 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002456 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2457 /*
2458 * Operating in streaming mode, attr is gonna disapear
2459 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002460 if (doc->dict != NULL)
2461 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2462 else
2463 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002464 ret->attr = NULL;
2465 } else {
2466 ret->attr = attr;
2467 ret->name = NULL;
2468 }
2469 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002470
2471 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002472#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002473 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002474 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002475 */
Daniel Veillard76575762002-09-05 14:21:15 +00002476 if (ctxt != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002477 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2478 "ID %s already defined\n",
2479 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002480 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002481#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002482 xmlFreeID(ret);
2483 return(NULL);
2484 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002485 if (attr != NULL)
2486 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002487 return(ret);
2488}
2489
2490/**
2491 * xmlFreeIDTable:
2492 * @table: An id table
2493 *
2494 * Deallocate the memory used by an ID hash table.
2495 */
2496void
2497xmlFreeIDTable(xmlIDTablePtr table) {
2498 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2499}
2500
2501/**
2502 * xmlIsID:
2503 * @doc: the document
2504 * @elem: the element carrying the attribute
2505 * @attr: the attribute
2506 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002507 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002508 * then this is done if DTD loading has been requested. In the case
2509 * of HTML documents parsed with the HTML parser, then ID detection is
2510 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002511 *
2512 * Returns 0 or 1 depending on the lookup result
2513 */
2514int
2515xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2516 if (doc == NULL) return(0);
2517 if (attr == NULL) return(0);
2518 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2519 return(0);
2520 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard9ba8e382003-10-28 21:31:45 +00002521 if (((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2522 (xmlStrEqual(BAD_CAST "name", attr->name))) &&
2523 ((elem != NULL) && (!xmlStrEqual(elem->name, BAD_CAST "input"))))
Owen Taylor3473f882001-02-23 17:55:21 +00002524 return(1);
2525 return(0);
2526 } else {
2527 xmlAttributePtr attrDecl;
2528
2529 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002530 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002531 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002532 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002533
2534 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002535 if (fullname == NULL)
2536 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002537 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2538 attr->name);
2539 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2540 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2541 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002542 if ((fullname != fn) && (fullname != elem->name))
2543 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002544 } else {
2545 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2546 attr->name);
2547 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2548 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2549 attr->name);
2550 }
Owen Taylor3473f882001-02-23 17:55:21 +00002551
2552 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2553 return(1);
2554 }
2555 return(0);
2556}
2557
2558/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002559 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002560 * @doc: the document
2561 * @attr: the attribute
2562 *
2563 * Remove the given attribute from the ID table maintained internally.
2564 *
2565 * Returns -1 if the lookup failed and 0 otherwise
2566 */
2567int
2568xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002569 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002570 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002571 xmlChar *ID;
2572
2573 if (doc == NULL) return(-1);
2574 if (attr == NULL) return(-1);
2575 table = (xmlIDTablePtr) doc->ids;
2576 if (table == NULL)
2577 return(-1);
2578
2579 if (attr == NULL)
2580 return(-1);
2581 ID = xmlNodeListGetString(doc, attr->children, 1);
2582 if (ID == NULL)
2583 return(-1);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002584 id = xmlHashLookup(table, ID);
2585 if (id == NULL || id->attr != attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002586 xmlFree(ID);
2587 return(-1);
2588 }
2589 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
2590 xmlFree(ID);
2591 return(0);
2592}
2593
2594/**
2595 * xmlGetID:
2596 * @doc: pointer to the document
2597 * @ID: the ID value
2598 *
2599 * Search the attribute declaring the given ID
2600 *
2601 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2602 */
2603xmlAttrPtr
2604xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2605 xmlIDTablePtr table;
2606 xmlIDPtr id;
2607
2608 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002609 return(NULL);
2610 }
2611
2612 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002613 return(NULL);
2614 }
2615
2616 table = (xmlIDTablePtr) doc->ids;
2617 if (table == NULL)
2618 return(NULL);
2619
2620 id = xmlHashLookup(table, ID);
2621 if (id == NULL)
2622 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002623 if (id->attr == NULL) {
2624 /*
2625 * We are operating on a stream, return a well known reference
2626 * since the attribute node doesn't exist anymore
2627 */
2628 return((xmlAttrPtr) doc);
2629 }
Owen Taylor3473f882001-02-23 17:55:21 +00002630 return(id->attr);
2631}
2632
2633/************************************************************************
2634 * *
2635 * Refs *
2636 * *
2637 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002638typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002639{
2640 xmlListPtr l;
2641 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002642} xmlRemoveMemo;
2643
2644typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2645
2646typedef struct xmlValidateMemo_t
2647{
2648 xmlValidCtxtPtr ctxt;
2649 const xmlChar *name;
2650} xmlValidateMemo;
2651
2652typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002653
2654/**
2655 * xmlCreateRefTable:
2656 *
2657 * create and initialize an empty ref hash table.
2658 *
2659 * Returns the xmlRefTablePtr just created or NULL in case
2660 * of error.
2661 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002662static xmlRefTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002663xmlCreateRefTable(void) {
2664 return(xmlHashCreate(0));
2665}
2666
2667/**
2668 * xmlFreeRef:
2669 * @lk: A list link
2670 *
2671 * Deallocate the memory used by a ref definition
2672 */
2673static void
2674xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002675 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2676 if (ref == NULL) return;
2677 if (ref->value != NULL)
2678 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002679 if (ref->name != NULL)
2680 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002681 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002682}
2683
2684/**
2685 * xmlFreeRefList:
2686 * @list_ref: A list of references.
2687 *
2688 * Deallocate the memory used by a list of references
2689 */
2690static void
2691xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002692 if (list_ref == NULL) return;
2693 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002694}
2695
2696/**
2697 * xmlWalkRemoveRef:
2698 * @data: Contents of current link
2699 * @user: Value supplied by the user
2700 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002701 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002702 */
2703static int
2704xmlWalkRemoveRef(const void *data, const void *user)
2705{
Daniel Veillard37721922001-05-04 15:21:12 +00002706 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2707 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2708 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002709
Daniel Veillard37721922001-05-04 15:21:12 +00002710 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2711 xmlListRemoveFirst(ref_list, (void *)data);
2712 return 0;
2713 }
2714 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002715}
2716
2717/**
Daniel Veillard770075b2004-02-25 10:44:30 +00002718 * xmlDummyCompare
2719 * @data0: Value supplied by the user
2720 * @data1: Value supplied by the user
2721 *
2722 * Do nothing, return 0. Used to create unordered lists.
2723 */
2724static int
2725xmlDummyCompare(const void *data0, const void *data1)
2726{
2727 return (0);
2728}
2729
2730/**
Owen Taylor3473f882001-02-23 17:55:21 +00002731 * xmlAddRef:
2732 * @ctxt: the validation context
2733 * @doc: pointer to the document
2734 * @value: the value name
2735 * @attr: the attribute holding the Ref
2736 *
2737 * Register a new ref declaration
2738 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002739 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002740 */
2741xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002742xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002743 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002744 xmlRefPtr ret;
2745 xmlRefTablePtr table;
2746 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002747
Daniel Veillard37721922001-05-04 15:21:12 +00002748 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002749 return(NULL);
2750 }
2751 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002752 return(NULL);
2753 }
2754 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002755 return(NULL);
2756 }
Owen Taylor3473f882001-02-23 17:55:21 +00002757
Daniel Veillard37721922001-05-04 15:21:12 +00002758 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002759 * Create the Ref table if needed.
2760 */
Daniel Veillard37721922001-05-04 15:21:12 +00002761 table = (xmlRefTablePtr) doc->refs;
2762 if (table == NULL)
2763 doc->refs = table = xmlCreateRefTable();
2764 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002765 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002766 "xmlAddRef: Table creation failed!\n");
2767 return(NULL);
2768 }
Owen Taylor3473f882001-02-23 17:55:21 +00002769
Daniel Veillard37721922001-05-04 15:21:12 +00002770 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2771 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002772 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002773 return(NULL);
2774 }
Owen Taylor3473f882001-02-23 17:55:21 +00002775
Daniel Veillard37721922001-05-04 15:21:12 +00002776 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002777 * fill the structure.
2778 */
Daniel Veillard37721922001-05-04 15:21:12 +00002779 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002780 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2781 /*
2782 * Operating in streaming mode, attr is gonna disapear
2783 */
2784 ret->name = xmlStrdup(attr->name);
2785 ret->attr = NULL;
2786 } else {
2787 ret->name = NULL;
2788 ret->attr = attr;
2789 }
2790 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002791
Daniel Veillard37721922001-05-04 15:21:12 +00002792 /* To add a reference :-
2793 * References are maintained as a list of references,
2794 * Lookup the entry, if no entry create new nodelist
2795 * Add the owning node to the NodeList
2796 * Return the ref
2797 */
Owen Taylor3473f882001-02-23 17:55:21 +00002798
Daniel Veillard37721922001-05-04 15:21:12 +00002799 if (NULL == (ref_list = xmlHashLookup(table, value))) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002800 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002801 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2802 "xmlAddRef: Reference list creation failed!\n",
2803 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002804 return(NULL);
2805 }
2806 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2807 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002808 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2809 "xmlAddRef: Reference list insertion failed!\n",
2810 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002811 return(NULL);
2812 }
2813 }
Daniel Veillard965983a2004-02-17 16:30:24 +00002814/* xmlListInsert(ref_list, ret); */
2815 xmlListAppend(ref_list, ret);
Daniel Veillard37721922001-05-04 15:21:12 +00002816 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002817}
2818
2819/**
2820 * xmlFreeRefTable:
2821 * @table: An ref table
2822 *
2823 * Deallocate the memory used by an Ref hash table.
2824 */
2825void
2826xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002827 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002828}
2829
2830/**
2831 * xmlIsRef:
2832 * @doc: the document
2833 * @elem: the element carrying the attribute
2834 * @attr: the attribute
2835 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002836 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00002837 * then this is simple, otherwise we use an heuristic: name Ref (upper
2838 * or lowercase).
2839 *
2840 * Returns 0 or 1 depending on the lookup result
2841 */
2842int
2843xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002844 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2845 return(0);
2846 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2847 /* TODO @@@ */
2848 return(0);
2849 } else {
2850 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00002851
Daniel Veillard37721922001-05-04 15:21:12 +00002852 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2853 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2854 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2855 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002856
Daniel Veillard37721922001-05-04 15:21:12 +00002857 if ((attrDecl != NULL) &&
2858 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2859 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2860 return(1);
2861 }
2862 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002863}
2864
2865/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002866 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00002867 * @doc: the document
2868 * @attr: the attribute
2869 *
2870 * Remove the given attribute from the Ref table maintained internally.
2871 *
2872 * Returns -1 if the lookup failed and 0 otherwise
2873 */
2874int
2875xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002876 xmlListPtr ref_list;
2877 xmlRefTablePtr table;
2878 xmlChar *ID;
2879 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00002880
Daniel Veillard37721922001-05-04 15:21:12 +00002881 if (doc == NULL) return(-1);
2882 if (attr == NULL) return(-1);
2883 table = (xmlRefTablePtr) doc->refs;
2884 if (table == NULL)
2885 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002886
Daniel Veillard37721922001-05-04 15:21:12 +00002887 if (attr == NULL)
2888 return(-1);
2889 ID = xmlNodeListGetString(doc, attr->children, 1);
2890 if (ID == NULL)
2891 return(-1);
2892 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00002893
Daniel Veillard37721922001-05-04 15:21:12 +00002894 if(ref_list == NULL) {
2895 xmlFree(ID);
2896 return (-1);
2897 }
2898 /* At this point, ref_list refers to a list of references which
2899 * have the same key as the supplied attr. Our list of references
2900 * is ordered by reference address and we don't have that information
2901 * here to use when removing. We'll have to walk the list and
2902 * check for a matching attribute, when we find one stop the walk
2903 * and remove the entry.
2904 * The list is ordered by reference, so that means we don't have the
2905 * key. Passing the list and the reference to the walker means we
2906 * will have enough data to be able to remove the entry.
2907 */
2908 target.l = ref_list;
2909 target.ap = attr;
2910
2911 /* Remove the supplied attr from our list */
2912 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00002913
Daniel Veillard37721922001-05-04 15:21:12 +00002914 /*If the list is empty then remove the list entry in the hash */
2915 if (xmlListEmpty(ref_list))
2916 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2917 xmlFreeRefList);
2918 xmlFree(ID);
2919 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002920}
2921
2922/**
2923 * xmlGetRefs:
2924 * @doc: pointer to the document
2925 * @ID: the ID value
2926 *
2927 * Find the set of references for the supplied ID.
2928 *
2929 * Returns NULL if not found, otherwise node set for the ID.
2930 */
2931xmlListPtr
2932xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00002933 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00002934
Daniel Veillard37721922001-05-04 15:21:12 +00002935 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002936 return(NULL);
2937 }
Owen Taylor3473f882001-02-23 17:55:21 +00002938
Daniel Veillard37721922001-05-04 15:21:12 +00002939 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002940 return(NULL);
2941 }
Owen Taylor3473f882001-02-23 17:55:21 +00002942
Daniel Veillard37721922001-05-04 15:21:12 +00002943 table = (xmlRefTablePtr) doc->refs;
2944 if (table == NULL)
2945 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002946
Daniel Veillard37721922001-05-04 15:21:12 +00002947 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00002948}
2949
2950/************************************************************************
2951 * *
2952 * Routines for validity checking *
2953 * *
2954 ************************************************************************/
2955
2956/**
2957 * xmlGetDtdElementDesc:
2958 * @dtd: a pointer to the DtD to search
2959 * @name: the element name
2960 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002961 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002962 *
2963 * returns the xmlElementPtr if found or NULL
2964 */
2965
2966xmlElementPtr
2967xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2968 xmlElementTablePtr table;
2969 xmlElementPtr cur;
2970 xmlChar *uqname = NULL, *prefix = NULL;
2971
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002972 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002973 if (dtd->elements == NULL)
2974 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002975 table = (xmlElementTablePtr) dtd->elements;
2976
2977 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002978 if (uqname != NULL)
2979 name = uqname;
2980 cur = xmlHashLookup2(table, name, prefix);
2981 if (prefix != NULL) xmlFree(prefix);
2982 if (uqname != NULL) xmlFree(uqname);
2983 return(cur);
2984}
2985/**
2986 * xmlGetDtdElementDesc2:
2987 * @dtd: a pointer to the DtD to search
2988 * @name: the element name
2989 * @create: create an empty description if not found
2990 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002991 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00002992 *
2993 * returns the xmlElementPtr if found or NULL
2994 */
2995
Daniel Veillard86fd5a72001-12-13 14:55:21 +00002996static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00002997xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
2998 xmlElementTablePtr table;
2999 xmlElementPtr cur;
3000 xmlChar *uqname = NULL, *prefix = NULL;
3001
3002 if (dtd == NULL) return(NULL);
3003 if (dtd->elements == NULL) {
3004 if (!create)
3005 return(NULL);
3006 /*
3007 * Create the Element table if needed.
3008 */
3009 table = (xmlElementTablePtr) dtd->elements;
3010 if (table == NULL) {
3011 table = xmlCreateElementTable();
3012 dtd->elements = (void *) table;
3013 }
3014 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003015 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003016 return(NULL);
3017 }
3018 }
3019 table = (xmlElementTablePtr) dtd->elements;
3020
3021 uqname = xmlSplitQName2(name, &prefix);
3022 if (uqname != NULL)
3023 name = uqname;
3024 cur = xmlHashLookup2(table, name, prefix);
3025 if ((cur == NULL) && (create)) {
3026 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3027 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003028 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003029 return(NULL);
3030 }
3031 memset(cur, 0, sizeof(xmlElement));
3032 cur->type = XML_ELEMENT_DECL;
3033
3034 /*
3035 * fill the structure.
3036 */
3037 cur->name = xmlStrdup(name);
3038 cur->prefix = xmlStrdup(prefix);
3039 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3040
3041 xmlHashAddEntry2(table, name, prefix, cur);
3042 }
3043 if (prefix != NULL) xmlFree(prefix);
3044 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003045 return(cur);
3046}
3047
3048/**
3049 * xmlGetDtdQElementDesc:
3050 * @dtd: a pointer to the DtD to search
3051 * @name: the element name
3052 * @prefix: the element namespace prefix
3053 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003054 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003055 *
3056 * returns the xmlElementPtr if found or NULL
3057 */
3058
Daniel Veillard48da9102001-08-07 01:10:10 +00003059xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003060xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3061 const xmlChar *prefix) {
3062 xmlElementTablePtr table;
3063
3064 if (dtd == NULL) return(NULL);
3065 if (dtd->elements == NULL) return(NULL);
3066 table = (xmlElementTablePtr) dtd->elements;
3067
3068 return(xmlHashLookup2(table, name, prefix));
3069}
3070
3071/**
3072 * xmlGetDtdAttrDesc:
3073 * @dtd: a pointer to the DtD to search
3074 * @elem: the element name
3075 * @name: the attribute name
3076 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003077 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003078 * this element.
3079 *
3080 * returns the xmlAttributePtr if found or NULL
3081 */
3082
3083xmlAttributePtr
3084xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3085 xmlAttributeTablePtr table;
3086 xmlAttributePtr cur;
3087 xmlChar *uqname = NULL, *prefix = NULL;
3088
3089 if (dtd == NULL) return(NULL);
3090 if (dtd->attributes == NULL) return(NULL);
3091
3092 table = (xmlAttributeTablePtr) dtd->attributes;
3093 if (table == NULL)
3094 return(NULL);
3095
3096 uqname = xmlSplitQName2(name, &prefix);
3097
3098 if (uqname != NULL) {
3099 cur = xmlHashLookup3(table, uqname, prefix, elem);
3100 if (prefix != NULL) xmlFree(prefix);
3101 if (uqname != NULL) xmlFree(uqname);
3102 } else
3103 cur = xmlHashLookup3(table, name, NULL, elem);
3104 return(cur);
3105}
3106
3107/**
3108 * xmlGetDtdQAttrDesc:
3109 * @dtd: a pointer to the DtD to search
3110 * @elem: the element name
3111 * @name: the attribute name
3112 * @prefix: the attribute namespace prefix
3113 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003114 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003115 * this element.
3116 *
3117 * returns the xmlAttributePtr if found or NULL
3118 */
3119
Daniel Veillard48da9102001-08-07 01:10:10 +00003120xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003121xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3122 const xmlChar *prefix) {
3123 xmlAttributeTablePtr table;
3124
3125 if (dtd == NULL) return(NULL);
3126 if (dtd->attributes == NULL) return(NULL);
3127 table = (xmlAttributeTablePtr) dtd->attributes;
3128
3129 return(xmlHashLookup3(table, name, prefix, elem));
3130}
3131
3132/**
3133 * xmlGetDtdNotationDesc:
3134 * @dtd: a pointer to the DtD to search
3135 * @name: the notation name
3136 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003137 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003138 *
3139 * returns the xmlNotationPtr if found or NULL
3140 */
3141
3142xmlNotationPtr
3143xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3144 xmlNotationTablePtr table;
3145
3146 if (dtd == NULL) return(NULL);
3147 if (dtd->notations == NULL) return(NULL);
3148 table = (xmlNotationTablePtr) dtd->notations;
3149
3150 return(xmlHashLookup(table, name));
3151}
3152
Daniel Veillard4432df22003-09-28 18:58:27 +00003153#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003154/**
3155 * xmlValidateNotationUse:
3156 * @ctxt: the validation context
3157 * @doc: the document
3158 * @notationName: the notation name to check
3159 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003160 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003161 * - [ VC: Notation Declared ]
3162 *
3163 * returns 1 if valid or 0 otherwise
3164 */
3165
3166int
3167xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3168 const xmlChar *notationName) {
3169 xmlNotationPtr notaDecl;
3170 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3171
3172 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3173 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3174 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3175
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003176 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003177 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3178 "NOTATION %s is not declared\n",
3179 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003180 return(0);
3181 }
3182 return(1);
3183}
Daniel Veillard4432df22003-09-28 18:58:27 +00003184#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003185
3186/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003187 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003188 * @doc: the document
3189 * @name: the element name
3190 *
3191 * Search in the DtDs whether an element accept Mixed content (or ANY)
3192 * basically if it is supposed to accept text childs
3193 *
3194 * returns 0 if no, 1 if yes, and -1 if no element description is available
3195 */
3196
3197int
3198xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3199 xmlElementPtr elemDecl;
3200
3201 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3202
3203 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3204 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3205 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3206 if (elemDecl == NULL) return(-1);
3207 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003208 case XML_ELEMENT_TYPE_UNDEFINED:
3209 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003210 case XML_ELEMENT_TYPE_ELEMENT:
3211 return(0);
3212 case XML_ELEMENT_TYPE_EMPTY:
3213 /*
3214 * return 1 for EMPTY since we want VC error to pop up
3215 * on <empty> </empty> for example
3216 */
3217 case XML_ELEMENT_TYPE_ANY:
3218 case XML_ELEMENT_TYPE_MIXED:
3219 return(1);
3220 }
3221 return(1);
3222}
3223
Daniel Veillard4432df22003-09-28 18:58:27 +00003224#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003225/**
3226 * xmlValidateNameValue:
3227 * @value: an Name value
3228 *
3229 * Validate that the given value match Name production
3230 *
3231 * returns 1 if valid or 0 otherwise
3232 */
3233
Daniel Veillard9b731d72002-04-14 12:56:08 +00003234int
Owen Taylor3473f882001-02-23 17:55:21 +00003235xmlValidateNameValue(const xmlChar *value) {
3236 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003237 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003238
3239 if (value == NULL) return(0);
3240 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003241 val = xmlStringCurrentChar(NULL, cur, &len);
3242 cur += len;
3243 if (!IS_LETTER(val) && (val != '_') &&
3244 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003245 return(0);
3246 }
3247
Daniel Veillardd8224e02002-01-13 15:43:22 +00003248 val = xmlStringCurrentChar(NULL, cur, &len);
3249 cur += len;
3250 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3251 (val == '.') || (val == '-') ||
3252 (val == '_') || (val == ':') ||
3253 (IS_COMBINING(val)) ||
3254 (IS_EXTENDER(val))) {
3255 val = xmlStringCurrentChar(NULL, cur, &len);
3256 cur += len;
3257 }
Owen Taylor3473f882001-02-23 17:55:21 +00003258
Daniel Veillardd8224e02002-01-13 15:43:22 +00003259 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003260
3261 return(1);
3262}
3263
3264/**
3265 * xmlValidateNamesValue:
3266 * @value: an Names value
3267 *
3268 * Validate that the given value match Names production
3269 *
3270 * returns 1 if valid or 0 otherwise
3271 */
3272
Daniel Veillard9b731d72002-04-14 12:56:08 +00003273int
Owen Taylor3473f882001-02-23 17:55:21 +00003274xmlValidateNamesValue(const xmlChar *value) {
3275 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003276 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003277
3278 if (value == NULL) return(0);
3279 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003280 val = xmlStringCurrentChar(NULL, cur, &len);
3281 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003282
Daniel Veillardd8224e02002-01-13 15:43:22 +00003283 if (!IS_LETTER(val) && (val != '_') &&
3284 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003285 return(0);
3286 }
3287
Daniel Veillardd8224e02002-01-13 15:43:22 +00003288 val = xmlStringCurrentChar(NULL, cur, &len);
3289 cur += len;
3290 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3291 (val == '.') || (val == '-') ||
3292 (val == '_') || (val == ':') ||
3293 (IS_COMBINING(val)) ||
3294 (IS_EXTENDER(val))) {
3295 val = xmlStringCurrentChar(NULL, cur, &len);
3296 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003297 }
3298
Daniel Veillardd8224e02002-01-13 15:43:22 +00003299 while (IS_BLANK(val)) {
3300 while (IS_BLANK(val)) {
3301 val = xmlStringCurrentChar(NULL, cur, &len);
3302 cur += len;
3303 }
3304
3305 if (!IS_LETTER(val) && (val != '_') &&
3306 (val != ':')) {
3307 return(0);
3308 }
3309 val = xmlStringCurrentChar(NULL, cur, &len);
3310 cur += len;
3311
3312 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3313 (val == '.') || (val == '-') ||
3314 (val == '_') || (val == ':') ||
3315 (IS_COMBINING(val)) ||
3316 (IS_EXTENDER(val))) {
3317 val = xmlStringCurrentChar(NULL, cur, &len);
3318 cur += len;
3319 }
3320 }
3321
3322 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003323
3324 return(1);
3325}
3326
3327/**
3328 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003329 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003330 *
3331 * Validate that the given value match Nmtoken production
3332 *
3333 * [ VC: Name Token ]
3334 *
3335 * returns 1 if valid or 0 otherwise
3336 */
3337
Daniel Veillard9b731d72002-04-14 12:56:08 +00003338int
Owen Taylor3473f882001-02-23 17:55:21 +00003339xmlValidateNmtokenValue(const xmlChar *value) {
3340 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003341 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003342
3343 if (value == NULL) return(0);
3344 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003345 val = xmlStringCurrentChar(NULL, cur, &len);
3346 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003347
Daniel Veillardd8224e02002-01-13 15:43:22 +00003348 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3349 (val != '.') && (val != '-') &&
3350 (val != '_') && (val != ':') &&
3351 (!IS_COMBINING(val)) &&
3352 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003353 return(0);
3354
Daniel Veillardd8224e02002-01-13 15:43:22 +00003355 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3356 (val == '.') || (val == '-') ||
3357 (val == '_') || (val == ':') ||
3358 (IS_COMBINING(val)) ||
3359 (IS_EXTENDER(val))) {
3360 val = xmlStringCurrentChar(NULL, cur, &len);
3361 cur += len;
3362 }
Owen Taylor3473f882001-02-23 17:55:21 +00003363
Daniel Veillardd8224e02002-01-13 15:43:22 +00003364 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003365
3366 return(1);
3367}
3368
3369/**
3370 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003371 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003372 *
3373 * Validate that the given value match Nmtokens production
3374 *
3375 * [ VC: Name Token ]
3376 *
3377 * returns 1 if valid or 0 otherwise
3378 */
3379
Daniel Veillard9b731d72002-04-14 12:56:08 +00003380int
Owen Taylor3473f882001-02-23 17:55:21 +00003381xmlValidateNmtokensValue(const xmlChar *value) {
3382 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003383 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003384
3385 if (value == NULL) return(0);
3386 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003387 val = xmlStringCurrentChar(NULL, cur, &len);
3388 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003389
Daniel Veillardd8224e02002-01-13 15:43:22 +00003390 while (IS_BLANK(val)) {
3391 val = xmlStringCurrentChar(NULL, cur, &len);
3392 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003393 }
3394
Daniel Veillardd8224e02002-01-13 15:43:22 +00003395 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3396 (val != '.') && (val != '-') &&
3397 (val != '_') && (val != ':') &&
3398 (!IS_COMBINING(val)) &&
3399 (!IS_EXTENDER(val)))
3400 return(0);
3401
3402 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3403 (val == '.') || (val == '-') ||
3404 (val == '_') || (val == ':') ||
3405 (IS_COMBINING(val)) ||
3406 (IS_EXTENDER(val))) {
3407 val = xmlStringCurrentChar(NULL, cur, &len);
3408 cur += len;
3409 }
3410
3411 while (IS_BLANK(val)) {
3412 while (IS_BLANK(val)) {
3413 val = xmlStringCurrentChar(NULL, cur, &len);
3414 cur += len;
3415 }
3416 if (val == 0) return(1);
3417
3418 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3419 (val != '.') && (val != '-') &&
3420 (val != '_') && (val != ':') &&
3421 (!IS_COMBINING(val)) &&
3422 (!IS_EXTENDER(val)))
3423 return(0);
3424
3425 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3426 (val == '.') || (val == '-') ||
3427 (val == '_') || (val == ':') ||
3428 (IS_COMBINING(val)) ||
3429 (IS_EXTENDER(val))) {
3430 val = xmlStringCurrentChar(NULL, cur, &len);
3431 cur += len;
3432 }
3433 }
3434
3435 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003436
3437 return(1);
3438}
3439
3440/**
3441 * xmlValidateNotationDecl:
3442 * @ctxt: the validation context
3443 * @doc: a document instance
3444 * @nota: a notation definition
3445 *
3446 * Try to validate a single notation definition
3447 * basically it does the following checks as described by the
3448 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003449 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003450 * But this function get called anyway ...
3451 *
3452 * returns 1 if valid or 0 otherwise
3453 */
3454
3455int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003456xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3457 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003458 int ret = 1;
3459
3460 return(ret);
3461}
3462
3463/**
3464 * xmlValidateAttributeValue:
3465 * @type: an attribute type
3466 * @value: an attribute value
3467 *
3468 * Validate that the given attribute value match the proper production
3469 *
3470 * [ VC: ID ]
3471 * Values of type ID must match the Name production....
3472 *
3473 * [ VC: IDREF ]
3474 * Values of type IDREF must match the Name production, and values
3475 * of type IDREFS must match Names ...
3476 *
3477 * [ VC: Entity Name ]
3478 * Values of type ENTITY must match the Name production, values
3479 * of type ENTITIES must match Names ...
3480 *
3481 * [ VC: Name Token ]
3482 * Values of type NMTOKEN must match the Nmtoken production; values
3483 * of type NMTOKENS must match Nmtokens.
3484 *
3485 * returns 1 if valid or 0 otherwise
3486 */
3487
3488int
3489xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3490 switch (type) {
3491 case XML_ATTRIBUTE_ENTITIES:
3492 case XML_ATTRIBUTE_IDREFS:
3493 return(xmlValidateNamesValue(value));
3494 case XML_ATTRIBUTE_ENTITY:
3495 case XML_ATTRIBUTE_IDREF:
3496 case XML_ATTRIBUTE_ID:
3497 case XML_ATTRIBUTE_NOTATION:
3498 return(xmlValidateNameValue(value));
3499 case XML_ATTRIBUTE_NMTOKENS:
3500 case XML_ATTRIBUTE_ENUMERATION:
3501 return(xmlValidateNmtokensValue(value));
3502 case XML_ATTRIBUTE_NMTOKEN:
3503 return(xmlValidateNmtokenValue(value));
3504 case XML_ATTRIBUTE_CDATA:
3505 break;
3506 }
3507 return(1);
3508}
3509
3510/**
3511 * xmlValidateAttributeValue2:
3512 * @ctxt: the validation context
3513 * @doc: the document
3514 * @name: the attribute name (used for error reporting only)
3515 * @type: the attribute type
3516 * @value: the attribute value
3517 *
3518 * Validate that the given attribute value match a given type.
3519 * This typically cannot be done before having finished parsing
3520 * the subsets.
3521 *
3522 * [ VC: IDREF ]
3523 * Values of type IDREF must match one of the declared IDs
3524 * Values of type IDREFS must match a sequence of the declared IDs
3525 * each Name must match the value of an ID attribute on some element
3526 * in the XML document; i.e. IDREF values must match the value of
3527 * some ID attribute
3528 *
3529 * [ VC: Entity Name ]
3530 * Values of type ENTITY must match one declared entity
3531 * Values of type ENTITIES must match a sequence of declared entities
3532 *
3533 * [ VC: Notation Attributes ]
3534 * all notation names in the declaration must be declared.
3535 *
3536 * returns 1 if valid or 0 otherwise
3537 */
3538
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003539static int
Owen Taylor3473f882001-02-23 17:55:21 +00003540xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3541 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3542 int ret = 1;
3543 switch (type) {
3544 case XML_ATTRIBUTE_IDREFS:
3545 case XML_ATTRIBUTE_IDREF:
3546 case XML_ATTRIBUTE_ID:
3547 case XML_ATTRIBUTE_NMTOKENS:
3548 case XML_ATTRIBUTE_ENUMERATION:
3549 case XML_ATTRIBUTE_NMTOKEN:
3550 case XML_ATTRIBUTE_CDATA:
3551 break;
3552 case XML_ATTRIBUTE_ENTITY: {
3553 xmlEntityPtr ent;
3554
3555 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003556 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003557 if ((ent == NULL) && (doc->standalone == 1)) {
3558 doc->standalone = 0;
3559 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003560 }
Owen Taylor3473f882001-02-23 17:55:21 +00003561 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003562 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3563 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003564 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003565 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003566 ret = 0;
3567 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003568 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3569 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003570 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003571 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003572 ret = 0;
3573 }
3574 break;
3575 }
3576 case XML_ATTRIBUTE_ENTITIES: {
3577 xmlChar *dup, *nam = NULL, *cur, save;
3578 xmlEntityPtr ent;
3579
3580 dup = xmlStrdup(value);
3581 if (dup == NULL)
3582 return(0);
3583 cur = dup;
3584 while (*cur != 0) {
3585 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003586 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003587 save = *cur;
3588 *cur = 0;
3589 ent = xmlGetDocEntity(doc, nam);
3590 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003591 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3592 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003593 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003594 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003595 ret = 0;
3596 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003597 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3598 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003599 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003600 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003601 ret = 0;
3602 }
3603 if (save == 0)
3604 break;
3605 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003606 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003607 }
3608 xmlFree(dup);
3609 break;
3610 }
3611 case XML_ATTRIBUTE_NOTATION: {
3612 xmlNotationPtr nota;
3613
3614 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3615 if ((nota == NULL) && (doc->extSubset != NULL))
3616 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3617
3618 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003619 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3620 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003621 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003622 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003623 ret = 0;
3624 }
3625 break;
3626 }
3627 }
3628 return(ret);
3629}
3630
3631/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003632 * xmlValidCtxtNormalizeAttributeValue:
3633 * @ctxt: the validation context
3634 * @doc: the document
3635 * @elem: the parent
3636 * @name: the attribute name
3637 * @value: the attribute value
3638 * @ctxt: the validation context or NULL
3639 *
3640 * Does the validation related extra step of the normalization of attribute
3641 * values:
3642 *
3643 * If the declared value is not CDATA, then the XML processor must further
3644 * process the normalized attribute value by discarding any leading and
3645 * trailing space (#x20) characters, and by replacing sequences of space
3646 * (#x20) characters by single space (#x20) character.
3647 *
3648 * Also check VC: Standalone Document Declaration in P32, and update
3649 * ctxt->valid accordingly
3650 *
3651 * returns a new normalized string if normalization is needed, NULL otherwise
3652 * the caller must free the returned value.
3653 */
3654
3655xmlChar *
3656xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3657 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3658 xmlChar *ret, *dst;
3659 const xmlChar *src;
3660 xmlAttributePtr attrDecl = NULL;
3661 int extsubset = 0;
3662
3663 if (doc == NULL) return(NULL);
3664 if (elem == NULL) return(NULL);
3665 if (name == NULL) return(NULL);
3666 if (value == NULL) return(NULL);
3667
3668 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003669 xmlChar fn[50];
3670 xmlChar *fullname;
3671
3672 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3673 if (fullname == NULL)
3674 return(0);
3675 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003676 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003677 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003678 if (attrDecl != NULL)
3679 extsubset = 1;
3680 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003681 if ((fullname != fn) && (fullname != elem->name))
3682 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003683 }
3684 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3685 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3686 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3687 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3688 if (attrDecl != NULL)
3689 extsubset = 1;
3690 }
3691
3692 if (attrDecl == NULL)
3693 return(NULL);
3694 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3695 return(NULL);
3696
3697 ret = xmlStrdup(value);
3698 if (ret == NULL)
3699 return(NULL);
3700 src = value;
3701 dst = ret;
3702 while (*src == 0x20) src++;
3703 while (*src != 0) {
3704 if (*src == 0x20) {
3705 while (*src == 0x20) src++;
3706 if (*src != 0)
3707 *dst++ = 0x20;
3708 } else {
3709 *dst++ = *src++;
3710 }
3711 }
3712 *dst = 0;
3713 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003714 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003715"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003716 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003717 ctxt->valid = 0;
3718 }
3719 return(ret);
3720}
3721
3722/**
Owen Taylor3473f882001-02-23 17:55:21 +00003723 * xmlValidNormalizeAttributeValue:
3724 * @doc: the document
3725 * @elem: the parent
3726 * @name: the attribute name
3727 * @value: the attribute value
3728 *
3729 * Does the validation related extra step of the normalization of attribute
3730 * values:
3731 *
3732 * If the declared value is not CDATA, then the XML processor must further
3733 * process the normalized attribute value by discarding any leading and
3734 * trailing space (#x20) characters, and by replacing sequences of space
3735 * (#x20) characters by single space (#x20) character.
3736 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003737 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003738 * the caller must free the returned value.
3739 */
3740
3741xmlChar *
3742xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3743 const xmlChar *name, const xmlChar *value) {
3744 xmlChar *ret, *dst;
3745 const xmlChar *src;
3746 xmlAttributePtr attrDecl = NULL;
3747
3748 if (doc == NULL) return(NULL);
3749 if (elem == NULL) return(NULL);
3750 if (name == NULL) return(NULL);
3751 if (value == NULL) return(NULL);
3752
3753 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003754 xmlChar fn[50];
3755 xmlChar *fullname;
3756
3757 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3758 if (fullname == NULL)
3759 return(0);
3760 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003761 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003762 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3763 if ((fullname != fn) && (fullname != elem->name))
3764 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003765 }
3766 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3767 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3768 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3769
3770 if (attrDecl == NULL)
3771 return(NULL);
3772 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3773 return(NULL);
3774
3775 ret = xmlStrdup(value);
3776 if (ret == NULL)
3777 return(NULL);
3778 src = value;
3779 dst = ret;
3780 while (*src == 0x20) src++;
3781 while (*src != 0) {
3782 if (*src == 0x20) {
3783 while (*src == 0x20) src++;
3784 if (*src != 0)
3785 *dst++ = 0x20;
3786 } else {
3787 *dst++ = *src++;
3788 }
3789 }
3790 *dst = 0;
3791 return(ret);
3792}
3793
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003794static void
Owen Taylor3473f882001-02-23 17:55:21 +00003795xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003796 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003797 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3798}
3799
3800/**
3801 * xmlValidateAttributeDecl:
3802 * @ctxt: the validation context
3803 * @doc: a document instance
3804 * @attr: an attribute definition
3805 *
3806 * Try to validate a single attribute definition
3807 * basically it does the following checks as described by the
3808 * XML-1.0 recommendation:
3809 * - [ VC: Attribute Default Legal ]
3810 * - [ VC: Enumeration ]
3811 * - [ VC: ID Attribute Default ]
3812 *
3813 * The ID/IDREF uniqueness and matching are done separately
3814 *
3815 * returns 1 if valid or 0 otherwise
3816 */
3817
3818int
3819xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3820 xmlAttributePtr attr) {
3821 int ret = 1;
3822 int val;
3823 CHECK_DTD;
3824 if(attr == NULL) return(1);
3825
3826 /* Attribute Default Legal */
3827 /* Enumeration */
3828 if (attr->defaultValue != NULL) {
3829 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3830 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003831 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003832 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003833 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003834 }
3835 ret &= val;
3836 }
3837
3838 /* ID Attribute Default */
3839 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3840 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3841 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003842 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003843 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003844 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003845 ret = 0;
3846 }
3847
3848 /* One ID per Element Type */
3849 if (attr->atype == XML_ATTRIBUTE_ID) {
3850 int nbId;
3851
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003852 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00003853 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3854 attr->elem);
3855 if (elem != NULL) {
3856 nbId = xmlScanIDAttributeDecl(NULL, elem);
3857 } else {
3858 xmlAttributeTablePtr table;
3859
3860 /*
3861 * The attribute may be declared in the internal subset and the
3862 * element in the external subset.
3863 */
3864 nbId = 0;
3865 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3866 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3867 xmlValidateAttributeIdCallback, &nbId);
3868 }
3869 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003870
3871 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003872 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3873 attr->elem, nbId, attr->name);
3874 } else if (doc->extSubset != NULL) {
3875 int extId = 0;
3876 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3877 if (elem != NULL) {
3878 extId = xmlScanIDAttributeDecl(NULL, elem);
3879 }
3880 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003881 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003882 "Element %s has %d ID attribute defined in the external subset : %s\n",
3883 attr->elem, extId, attr->name);
3884 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003885 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003886"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003887 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003888 }
3889 }
3890 }
3891
3892 /* Validity Constraint: Enumeration */
3893 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3894 xmlEnumerationPtr tree = attr->tree;
3895 while (tree != NULL) {
3896 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3897 tree = tree->next;
3898 }
3899 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003900 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003901"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003902 attr->defaultValue, attr->name, attr->elem);
3903 ret = 0;
3904 }
3905 }
3906
3907 return(ret);
3908}
3909
3910/**
3911 * xmlValidateElementDecl:
3912 * @ctxt: the validation context
3913 * @doc: a document instance
3914 * @elem: an element definition
3915 *
3916 * Try to validate a single element definition
3917 * basically it does the following checks as described by the
3918 * XML-1.0 recommendation:
3919 * - [ VC: One ID per Element Type ]
3920 * - [ VC: No Duplicate Types ]
3921 * - [ VC: Unique Element Type Declaration ]
3922 *
3923 * returns 1 if valid or 0 otherwise
3924 */
3925
3926int
3927xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3928 xmlElementPtr elem) {
3929 int ret = 1;
3930 xmlElementPtr tst;
3931
3932 CHECK_DTD;
3933
3934 if (elem == NULL) return(1);
3935
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003936#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00003937#ifdef LIBXML_REGEXP_ENABLED
3938 /* Build the regexp associated to the content model */
3939 ret = xmlValidBuildContentModel(ctxt, elem);
3940#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003941#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00003942
Owen Taylor3473f882001-02-23 17:55:21 +00003943 /* No Duplicate Types */
3944 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3945 xmlElementContentPtr cur, next;
3946 const xmlChar *name;
3947
3948 cur = elem->content;
3949 while (cur != NULL) {
3950 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3951 if (cur->c1 == NULL) break;
3952 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3953 name = cur->c1->name;
3954 next = cur->c2;
3955 while (next != NULL) {
3956 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00003957 if ((xmlStrEqual(next->name, name)) &&
3958 (xmlStrEqual(next->prefix, cur->prefix))) {
3959 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003960 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00003961 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003962 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003963 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003964 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003965 "Definition of %s has duplicate references of %s:%s\n",
3966 elem->name, cur->prefix, name);
3967 }
Owen Taylor3473f882001-02-23 17:55:21 +00003968 ret = 0;
3969 }
3970 break;
3971 }
3972 if (next->c1 == NULL) break;
3973 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00003974 if ((xmlStrEqual(next->c1->name, name)) &&
3975 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
3976 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003977 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003978 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003979 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003980 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003981 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003982 "Definition of %s has duplicate references to %s:%s\n",
3983 elem->name, cur->prefix, name);
3984 }
Owen Taylor3473f882001-02-23 17:55:21 +00003985 ret = 0;
3986 }
3987 next = next->c2;
3988 }
3989 }
3990 cur = cur->c2;
3991 }
3992 }
3993
3994 /* VC: Unique Element Type Declaration */
3995 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003996 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00003997 ((tst->prefix == elem->prefix) ||
3998 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00003999 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004000 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4001 "Redefinition of element %s\n",
4002 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004003 ret = 0;
4004 }
4005 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004006 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004007 ((tst->prefix == elem->prefix) ||
4008 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004009 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004010 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4011 "Redefinition of element %s\n",
4012 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004013 ret = 0;
4014 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004015 /* One ID per Element Type
4016 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004017 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4018 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004019 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004020 return(ret);
4021}
4022
4023/**
4024 * xmlValidateOneAttribute:
4025 * @ctxt: the validation context
4026 * @doc: a document instance
4027 * @elem: an element instance
4028 * @attr: an attribute instance
4029 * @value: the attribute value (without entities processing)
4030 *
4031 * Try to validate a single attribute for an element
4032 * basically it does the following checks as described by the
4033 * XML-1.0 recommendation:
4034 * - [ VC: Attribute Value Type ]
4035 * - [ VC: Fixed Attribute Default ]
4036 * - [ VC: Entity Name ]
4037 * - [ VC: Name Token ]
4038 * - [ VC: ID ]
4039 * - [ VC: IDREF ]
4040 * - [ VC: Entity Name ]
4041 * - [ VC: Notation Attributes ]
4042 *
4043 * The ID/IDREF uniqueness and matching are done separately
4044 *
4045 * returns 1 if valid or 0 otherwise
4046 */
4047
4048int
4049xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004050 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4051{
Owen Taylor3473f882001-02-23 17:55:21 +00004052 xmlAttributePtr attrDecl = NULL;
4053 int val;
4054 int ret = 1;
4055
4056 CHECK_DTD;
4057 if ((elem == NULL) || (elem->name == NULL)) return(0);
4058 if ((attr == NULL) || (attr->name == NULL)) return(0);
4059
4060 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004061 xmlChar fn[50];
4062 xmlChar *fullname;
4063
4064 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4065 if (fullname == NULL)
4066 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004067 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004068 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004069 attr->name, attr->ns->prefix);
4070 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004071 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004072 attr->name, attr->ns->prefix);
4073 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004074 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004075 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4076 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004077 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004078 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004079 if ((fullname != fn) && (fullname != elem->name))
4080 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004081 }
4082 if (attrDecl == NULL) {
4083 if (attr->ns != NULL) {
4084 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4085 attr->name, attr->ns->prefix);
4086 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4087 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4088 attr->name, attr->ns->prefix);
4089 } else {
4090 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4091 elem->name, attr->name);
4092 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4093 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4094 elem->name, attr->name);
4095 }
4096 }
4097
4098
4099 /* Validity Constraint: Attribute Value Type */
4100 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004101 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004102 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004103 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004104 return(0);
4105 }
4106 attr->atype = attrDecl->atype;
4107
4108 val = xmlValidateAttributeValue(attrDecl->atype, value);
4109 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004110 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004111 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004112 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004113 ret = 0;
4114 }
4115
4116 /* Validity constraint: Fixed Attribute Default */
4117 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4118 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004119 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004120 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004121 attr->name, elem->name, attrDecl->defaultValue);
4122 ret = 0;
4123 }
4124 }
4125
4126 /* Validity Constraint: ID uniqueness */
4127 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4128 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4129 ret = 0;
4130 }
4131
4132 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4133 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4134 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4135 ret = 0;
4136 }
4137
4138 /* Validity Constraint: Notation Attributes */
4139 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4140 xmlEnumerationPtr tree = attrDecl->tree;
4141 xmlNotationPtr nota;
4142
4143 /* First check that the given NOTATION was declared */
4144 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4145 if (nota == NULL)
4146 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4147
4148 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004149 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004150 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004151 value, attr->name, elem->name);
4152 ret = 0;
4153 }
4154
4155 /* Second, verify that it's among the list */
4156 while (tree != NULL) {
4157 if (xmlStrEqual(tree->name, value)) break;
4158 tree = tree->next;
4159 }
4160 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004161 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004162"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004163 value, attr->name, elem->name);
4164 ret = 0;
4165 }
4166 }
4167
4168 /* Validity Constraint: Enumeration */
4169 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4170 xmlEnumerationPtr tree = attrDecl->tree;
4171 while (tree != NULL) {
4172 if (xmlStrEqual(tree->name, value)) break;
4173 tree = tree->next;
4174 }
4175 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004176 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004177 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004178 value, attr->name, elem->name);
4179 ret = 0;
4180 }
4181 }
4182
4183 /* Fixed Attribute Default */
4184 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4185 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004186 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004187 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004188 attr->name, elem->name, attrDecl->defaultValue);
4189 ret = 0;
4190 }
4191
4192 /* Extra check for the attribute value */
4193 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4194 attrDecl->atype, value);
4195
4196 return(ret);
4197}
4198
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004199/**
4200 * xmlValidateOneNamespace:
4201 * @ctxt: the validation context
4202 * @doc: a document instance
4203 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004204 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004205 * @ns: an namespace declaration instance
4206 * @value: the attribute value (without entities processing)
4207 *
4208 * Try to validate a single namespace declaration for an element
4209 * basically it does the following checks as described by the
4210 * XML-1.0 recommendation:
4211 * - [ VC: Attribute Value Type ]
4212 * - [ VC: Fixed Attribute Default ]
4213 * - [ VC: Entity Name ]
4214 * - [ VC: Name Token ]
4215 * - [ VC: ID ]
4216 * - [ VC: IDREF ]
4217 * - [ VC: Entity Name ]
4218 * - [ VC: Notation Attributes ]
4219 *
4220 * The ID/IDREF uniqueness and matching are done separately
4221 *
4222 * returns 1 if valid or 0 otherwise
4223 */
4224
4225int
4226xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4227xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4228 /* xmlElementPtr elemDecl; */
4229 xmlAttributePtr attrDecl = NULL;
4230 int val;
4231 int ret = 1;
4232
4233 CHECK_DTD;
4234 if ((elem == NULL) || (elem->name == NULL)) return(0);
4235 if ((ns == NULL) || (ns->href == NULL)) return(0);
4236
4237 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004238 xmlChar fn[50];
4239 xmlChar *fullname;
4240
4241 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4242 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004243 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004244 return(0);
4245 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004246 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004247 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004248 ns->prefix, BAD_CAST "xmlns");
4249 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004250 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004251 ns->prefix, BAD_CAST "xmlns");
4252 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004253 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004254 BAD_CAST "xmlns");
4255 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004256 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004257 BAD_CAST "xmlns");
4258 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004259 if ((fullname != fn) && (fullname != elem->name))
4260 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004261 }
4262 if (attrDecl == NULL) {
4263 if (ns->prefix != NULL) {
4264 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4265 ns->prefix, BAD_CAST "xmlns");
4266 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4267 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4268 ns->prefix, BAD_CAST "xmlns");
4269 } else {
4270 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4271 elem->name, BAD_CAST "xmlns");
4272 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4273 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4274 elem->name, BAD_CAST "xmlns");
4275 }
4276 }
4277
4278
4279 /* Validity Constraint: Attribute Value Type */
4280 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004281 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004282 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004283 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004284 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004285 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004286 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004287 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004288 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004289 }
4290 return(0);
4291 }
4292
4293 val = xmlValidateAttributeValue(attrDecl->atype, value);
4294 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004295 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004296 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004297 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004298 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004299 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004300 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004301 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004302 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004303 }
4304 ret = 0;
4305 }
4306
4307 /* Validity constraint: Fixed Attribute Default */
4308 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4309 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004310 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004311 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004312 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4313 ns->prefix, elem->name, attrDecl->defaultValue);
4314 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004315 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004316 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004317 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004318 }
4319 ret = 0;
4320 }
4321 }
4322
4323 /* Validity Constraint: ID uniqueness */
4324 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4325 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4326 ret = 0;
4327 }
4328
4329 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4330 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4331 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4332 ret = 0;
4333 }
4334
4335 /* Validity Constraint: Notation Attributes */
4336 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4337 xmlEnumerationPtr tree = attrDecl->tree;
4338 xmlNotationPtr nota;
4339
4340 /* First check that the given NOTATION was declared */
4341 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4342 if (nota == NULL)
4343 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4344
4345 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004346 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004347 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004348 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4349 value, ns->prefix, elem->name);
4350 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004351 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004352 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004353 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004354 }
4355 ret = 0;
4356 }
4357
4358 /* Second, verify that it's among the list */
4359 while (tree != NULL) {
4360 if (xmlStrEqual(tree->name, value)) break;
4361 tree = tree->next;
4362 }
4363 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004364 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004365 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004366"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4367 value, ns->prefix, elem->name);
4368 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004369 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004370"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004371 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004372 }
4373 ret = 0;
4374 }
4375 }
4376
4377 /* Validity Constraint: Enumeration */
4378 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4379 xmlEnumerationPtr tree = attrDecl->tree;
4380 while (tree != NULL) {
4381 if (xmlStrEqual(tree->name, value)) break;
4382 tree = tree->next;
4383 }
4384 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004385 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004386 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004387"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4388 value, ns->prefix, elem->name);
4389 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004390 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004391"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004392 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004393 }
4394 ret = 0;
4395 }
4396 }
4397
4398 /* Fixed Attribute Default */
4399 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4400 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004401 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004402 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004403 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4404 ns->prefix, elem->name, attrDecl->defaultValue);
4405 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004406 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004407 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004408 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004409 }
4410 ret = 0;
4411 }
4412
4413 /* Extra check for the attribute value */
4414 if (ns->prefix != NULL) {
4415 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4416 attrDecl->atype, value);
4417 } else {
4418 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4419 attrDecl->atype, value);
4420 }
4421
4422 return(ret);
4423}
4424
Daniel Veillard118aed72002-09-24 14:13:13 +00004425#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004426/**
4427 * xmlValidateSkipIgnorable:
4428 * @ctxt: the validation context
4429 * @child: the child list
4430 *
4431 * Skip ignorable elements w.r.t. the validation process
4432 *
4433 * returns the first element to consider for validation of the content model
4434 */
4435
4436static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004437xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004438 while (child != NULL) {
4439 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004440 /* These things are ignored (skipped) during validation. */
4441 case XML_PI_NODE:
4442 case XML_COMMENT_NODE:
4443 case XML_XINCLUDE_START:
4444 case XML_XINCLUDE_END:
4445 child = child->next;
4446 break;
4447 case XML_TEXT_NODE:
4448 if (xmlIsBlankNode(child))
4449 child = child->next;
4450 else
4451 return(child);
4452 break;
4453 /* keep current node */
4454 default:
4455 return(child);
4456 }
4457 }
4458 return(child);
4459}
4460
4461/**
4462 * xmlValidateElementType:
4463 * @ctxt: the validation context
4464 *
4465 * Try to validate the content model of an element internal function
4466 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004467 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4468 * reference is found and -3 if the validation succeeded but
4469 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004470 */
4471
4472static int
4473xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004474 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004475 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004476
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004477 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004478 if ((NODE == NULL) && (CONT == NULL))
4479 return(1);
4480 if ((NODE == NULL) &&
4481 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4482 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4483 return(1);
4484 }
4485 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004486 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004487 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004488
4489 /*
4490 * We arrive here when more states need to be examined
4491 */
4492cont:
4493
4494 /*
4495 * We just recovered from a rollback generated by a possible
4496 * epsilon transition, go directly to the analysis phase
4497 */
4498 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004499 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004500 DEBUG_VALID_STATE(NODE, CONT)
4501 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004502 goto analyze;
4503 }
4504
4505 DEBUG_VALID_STATE(NODE, CONT)
4506 /*
4507 * we may have to save a backup state here. This is the equivalent
4508 * of handling epsilon transition in NFAs.
4509 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004510 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004511 ((CONT->parent == NULL) ||
4512 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004513 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004514 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004515 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004516 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004517 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4518 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004519 }
4520
4521
4522 /*
4523 * Check first if the content matches
4524 */
4525 switch (CONT->type) {
4526 case XML_ELEMENT_CONTENT_PCDATA:
4527 if (NODE == NULL) {
4528 DEBUG_VALID_MSG("pcdata failed no node");
4529 ret = 0;
4530 break;
4531 }
4532 if (NODE->type == XML_TEXT_NODE) {
4533 DEBUG_VALID_MSG("pcdata found, skip to next");
4534 /*
4535 * go to next element in the content model
4536 * skipping ignorable elems
4537 */
4538 do {
4539 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004540 NODE = xmlValidateSkipIgnorable(NODE);
4541 if ((NODE != NULL) &&
4542 (NODE->type == XML_ENTITY_REF_NODE))
4543 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004544 } while ((NODE != NULL) &&
4545 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004546 (NODE->type != XML_TEXT_NODE) &&
4547 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004548 ret = 1;
4549 break;
4550 } else {
4551 DEBUG_VALID_MSG("pcdata failed");
4552 ret = 0;
4553 break;
4554 }
4555 break;
4556 case XML_ELEMENT_CONTENT_ELEMENT:
4557 if (NODE == NULL) {
4558 DEBUG_VALID_MSG("element failed no node");
4559 ret = 0;
4560 break;
4561 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004562 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4563 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004564 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004565 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4566 ret = (CONT->prefix == NULL);
4567 } else if (CONT->prefix == NULL) {
4568 ret = 0;
4569 } else {
4570 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4571 }
4572 }
4573 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004574 DEBUG_VALID_MSG("element found, skip to next");
4575 /*
4576 * go to next element in the content model
4577 * skipping ignorable elems
4578 */
4579 do {
4580 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004581 NODE = xmlValidateSkipIgnorable(NODE);
4582 if ((NODE != NULL) &&
4583 (NODE->type == XML_ENTITY_REF_NODE))
4584 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004585 } while ((NODE != NULL) &&
4586 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004587 (NODE->type != XML_TEXT_NODE) &&
4588 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004589 } else {
4590 DEBUG_VALID_MSG("element failed");
4591 ret = 0;
4592 break;
4593 }
4594 break;
4595 case XML_ELEMENT_CONTENT_OR:
4596 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004597 * Small optimization.
4598 */
4599 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4600 if ((NODE == NULL) ||
4601 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4602 DEPTH++;
4603 CONT = CONT->c2;
4604 goto cont;
4605 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004606 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4607 ret = (CONT->c1->prefix == NULL);
4608 } else if (CONT->c1->prefix == NULL) {
4609 ret = 0;
4610 } else {
4611 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4612 }
4613 if (ret == 0) {
4614 DEPTH++;
4615 CONT = CONT->c2;
4616 goto cont;
4617 }
Daniel Veillard85349052001-04-20 13:48:21 +00004618 }
4619
4620 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004621 * save the second branch 'or' branch
4622 */
4623 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004624 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4625 OCCURS, ROLLBACK_OR) < 0)
4626 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004627 DEPTH++;
4628 CONT = CONT->c1;
4629 goto cont;
4630 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004631 /*
4632 * Small optimization.
4633 */
4634 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4635 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4636 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4637 if ((NODE == NULL) ||
4638 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4639 DEPTH++;
4640 CONT = CONT->c2;
4641 goto cont;
4642 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004643 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4644 ret = (CONT->c1->prefix == NULL);
4645 } else if (CONT->c1->prefix == NULL) {
4646 ret = 0;
4647 } else {
4648 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4649 }
4650 if (ret == 0) {
4651 DEPTH++;
4652 CONT = CONT->c2;
4653 goto cont;
4654 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004655 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004656 DEPTH++;
4657 CONT = CONT->c1;
4658 goto cont;
4659 }
4660
4661 /*
4662 * At this point handle going up in the tree
4663 */
4664 if (ret == -1) {
4665 DEBUG_VALID_MSG("error found returning");
4666 return(ret);
4667 }
4668analyze:
4669 while (CONT != NULL) {
4670 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004671 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004672 * this level.
4673 */
4674 if (ret == 0) {
4675 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004676 xmlNodePtr cur;
4677
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004678 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004679 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004680 DEBUG_VALID_MSG("Once branch failed, rollback");
4681 if (vstateVPop(ctxt) < 0 ) {
4682 DEBUG_VALID_MSG("exhaustion, failed");
4683 return(0);
4684 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004685 if (cur != ctxt->vstate->node)
4686 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004687 goto cont;
4688 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004689 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004690 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004691 DEBUG_VALID_MSG("Plus branch failed, rollback");
4692 if (vstateVPop(ctxt) < 0 ) {
4693 DEBUG_VALID_MSG("exhaustion, failed");
4694 return(0);
4695 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004696 if (cur != ctxt->vstate->node)
4697 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004698 goto cont;
4699 }
4700 DEBUG_VALID_MSG("Plus branch found");
4701 ret = 1;
4702 break;
4703 case XML_ELEMENT_CONTENT_MULT:
4704#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004705 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004706 DEBUG_VALID_MSG("Mult branch failed");
4707 } else {
4708 DEBUG_VALID_MSG("Mult branch found");
4709 }
4710#endif
4711 ret = 1;
4712 break;
4713 case XML_ELEMENT_CONTENT_OPT:
4714 DEBUG_VALID_MSG("Option branch failed");
4715 ret = 1;
4716 break;
4717 }
4718 } else {
4719 switch (CONT->ocur) {
4720 case XML_ELEMENT_CONTENT_OPT:
4721 DEBUG_VALID_MSG("Option branch succeeded");
4722 ret = 1;
4723 break;
4724 case XML_ELEMENT_CONTENT_ONCE:
4725 DEBUG_VALID_MSG("Once branch succeeded");
4726 ret = 1;
4727 break;
4728 case XML_ELEMENT_CONTENT_PLUS:
4729 if (STATE == ROLLBACK_PARENT) {
4730 DEBUG_VALID_MSG("Plus branch rollback");
4731 ret = 1;
4732 break;
4733 }
4734 if (NODE == NULL) {
4735 DEBUG_VALID_MSG("Plus branch exhausted");
4736 ret = 1;
4737 break;
4738 }
4739 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004740 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004741 goto cont;
4742 case XML_ELEMENT_CONTENT_MULT:
4743 if (STATE == ROLLBACK_PARENT) {
4744 DEBUG_VALID_MSG("Mult branch rollback");
4745 ret = 1;
4746 break;
4747 }
4748 if (NODE == NULL) {
4749 DEBUG_VALID_MSG("Mult branch exhausted");
4750 ret = 1;
4751 break;
4752 }
4753 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004754 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004755 goto cont;
4756 }
4757 }
4758 STATE = 0;
4759
4760 /*
4761 * Then act accordingly at the parent level
4762 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004763 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004764 if (CONT->parent == NULL)
4765 break;
4766
4767 switch (CONT->parent->type) {
4768 case XML_ELEMENT_CONTENT_PCDATA:
4769 DEBUG_VALID_MSG("Error: parent pcdata");
4770 return(-1);
4771 case XML_ELEMENT_CONTENT_ELEMENT:
4772 DEBUG_VALID_MSG("Error: parent element");
4773 return(-1);
4774 case XML_ELEMENT_CONTENT_OR:
4775 if (ret == 1) {
4776 DEBUG_VALID_MSG("Or succeeded");
4777 CONT = CONT->parent;
4778 DEPTH--;
4779 } else {
4780 DEBUG_VALID_MSG("Or failed");
4781 CONT = CONT->parent;
4782 DEPTH--;
4783 }
4784 break;
4785 case XML_ELEMENT_CONTENT_SEQ:
4786 if (ret == 0) {
4787 DEBUG_VALID_MSG("Sequence failed");
4788 CONT = CONT->parent;
4789 DEPTH--;
4790 } else if (CONT == CONT->parent->c1) {
4791 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4792 CONT = CONT->parent->c2;
4793 goto cont;
4794 } else {
4795 DEBUG_VALID_MSG("Sequence succeeded");
4796 CONT = CONT->parent;
4797 DEPTH--;
4798 }
4799 }
4800 }
4801 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004802 xmlNodePtr cur;
4803
4804 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004805 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4806 if (vstateVPop(ctxt) < 0 ) {
4807 DEBUG_VALID_MSG("exhaustion, failed");
4808 return(0);
4809 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004810 if (cur != ctxt->vstate->node)
4811 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004812 goto cont;
4813 }
4814 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004815 xmlNodePtr cur;
4816
4817 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004818 DEBUG_VALID_MSG("Failure, rollback");
4819 if (vstateVPop(ctxt) < 0 ) {
4820 DEBUG_VALID_MSG("exhaustion, failed");
4821 return(0);
4822 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004823 if (cur != ctxt->vstate->node)
4824 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004825 goto cont;
4826 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004827 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004828}
Daniel Veillard23e73572002-09-19 19:56:43 +00004829#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004830
4831/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00004832 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004833 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00004834 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004835 * @content: An element
4836 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4837 *
4838 * This will dump the list of elements to the buffer
4839 * Intended just for the debug routine
4840 */
4841static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00004842xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004843 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00004844 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004845
4846 if (node == NULL) return;
4847 if (glob) strcat(buf, "(");
4848 cur = node;
4849 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004850 len = strlen(buf);
4851 if (size - len < 50) {
4852 if ((size - len > 4) && (buf[len - 1] != '.'))
4853 strcat(buf, " ...");
4854 return;
4855 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004856 switch (cur->type) {
4857 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004858 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004859 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004860 if ((size - len > 4) && (buf[len - 1] != '.'))
4861 strcat(buf, " ...");
4862 return;
4863 }
4864 strcat(buf, (char *) cur->ns->prefix);
4865 strcat(buf, ":");
4866 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004867 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004868 if ((size - len > 4) && (buf[len - 1] != '.'))
4869 strcat(buf, " ...");
4870 return;
4871 }
4872 strcat(buf, (char *) cur->name);
4873 if (cur->next != NULL)
4874 strcat(buf, " ");
4875 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004876 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004877 if (xmlIsBlankNode(cur))
4878 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004879 case XML_CDATA_SECTION_NODE:
4880 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004881 strcat(buf, "CDATA");
4882 if (cur->next != NULL)
4883 strcat(buf, " ");
4884 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004885 case XML_ATTRIBUTE_NODE:
4886 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004887#ifdef LIBXML_DOCB_ENABLED
4888 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004889#endif
4890 case XML_HTML_DOCUMENT_NODE:
4891 case XML_DOCUMENT_TYPE_NODE:
4892 case XML_DOCUMENT_FRAG_NODE:
4893 case XML_NOTATION_NODE:
4894 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004895 strcat(buf, "???");
4896 if (cur->next != NULL)
4897 strcat(buf, " ");
4898 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004899 case XML_ENTITY_NODE:
4900 case XML_PI_NODE:
4901 case XML_DTD_NODE:
4902 case XML_COMMENT_NODE:
4903 case XML_ELEMENT_DECL:
4904 case XML_ATTRIBUTE_DECL:
4905 case XML_ENTITY_DECL:
4906 case XML_XINCLUDE_START:
4907 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004908 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004909 }
4910 cur = cur->next;
4911 }
4912 if (glob) strcat(buf, ")");
4913}
4914
4915/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004916 * xmlValidateElementContent:
4917 * @ctxt: the validation context
4918 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004919 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004920 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004921 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004922 *
4923 * Try to validate the content model of an element
4924 *
4925 * returns 1 if valid or 0 if not and -1 in case of error
4926 */
4927
4928static int
4929xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004930 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004931 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00004932#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00004933 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00004934#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00004935 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004936 xmlElementContentPtr cont;
4937 const xmlChar *name;
4938
4939 if (elemDecl == NULL)
4940 return(-1);
4941 cont = elemDecl->content;
4942 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004943
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004944#ifdef LIBXML_REGEXP_ENABLED
4945 /* Build the regexp associated to the content model */
4946 if (elemDecl->contModel == NULL)
4947 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4948 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004949 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004950 } else {
4951 xmlRegExecCtxtPtr exec;
4952
Daniel Veillardec498e12003-02-05 11:01:50 +00004953 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
4954 return(-1);
4955 }
Daniel Veillard01992e02002-10-09 10:20:30 +00004956 ctxt->nodeMax = 0;
4957 ctxt->nodeNr = 0;
4958 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004959 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4960 if (exec != NULL) {
4961 cur = child;
4962 while (cur != NULL) {
4963 switch (cur->type) {
4964 case XML_ENTITY_REF_NODE:
4965 /*
4966 * Push the current node to be able to roll back
4967 * and process within the entity
4968 */
4969 if ((cur->children != NULL) &&
4970 (cur->children->children != NULL)) {
4971 nodeVPush(ctxt, cur);
4972 cur = cur->children->children;
4973 continue;
4974 }
4975 break;
4976 case XML_TEXT_NODE:
4977 if (xmlIsBlankNode(cur))
4978 break;
4979 ret = 0;
4980 goto fail;
4981 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00004982 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004983 ret = 0;
4984 goto fail;
4985 case XML_ELEMENT_NODE:
4986 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004987 xmlChar fn[50];
4988 xmlChar *fullname;
4989
4990 fullname = xmlBuildQName(cur->name,
4991 cur->ns->prefix, fn, 50);
4992 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004993 ret = -1;
4994 goto fail;
4995 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004996 ret = xmlRegExecPushString(exec, fullname, NULL);
4997 if ((fullname != fn) && (fullname != cur->name))
4998 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004999 } else {
5000 ret = xmlRegExecPushString(exec, cur->name, NULL);
5001 }
5002 break;
5003 default:
5004 break;
5005 }
5006 /*
5007 * Switch to next element
5008 */
5009 cur = cur->next;
5010 while (cur == NULL) {
5011 cur = nodeVPop(ctxt);
5012 if (cur == NULL)
5013 break;
5014 cur = cur->next;
5015 }
5016 }
5017 ret = xmlRegExecPushString(exec, NULL, NULL);
5018fail:
5019 xmlRegFreeExecCtxt(exec);
5020 }
5021 }
5022#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005023 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005024 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005025 */
5026 ctxt->vstateMax = 8;
5027 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5028 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5029 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005030 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005031 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005032 }
5033 /*
5034 * The first entry in the stack is reserved to the current state
5035 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005036 ctxt->nodeMax = 0;
5037 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005038 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005039 ctxt->vstate = &ctxt->vstateTab[0];
5040 ctxt->vstateNr = 1;
5041 CONT = cont;
5042 NODE = child;
5043 DEPTH = 0;
5044 OCCURS = 0;
5045 STATE = 0;
5046 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005047 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005048 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5049 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005050 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005051 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005052 /*
5053 * An entities reference appeared at this level.
5054 * Buid a minimal representation of this node content
5055 * sufficient to run the validation process on it
5056 */
5057 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005058 cur = child;
5059 while (cur != NULL) {
5060 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005061 case XML_ENTITY_REF_NODE:
5062 /*
5063 * Push the current node to be able to roll back
5064 * and process within the entity
5065 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005066 if ((cur->children != NULL) &&
5067 (cur->children->children != NULL)) {
5068 nodeVPush(ctxt, cur);
5069 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005070 continue;
5071 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005072 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005073 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005074 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005075 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005076 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005077 case XML_CDATA_SECTION_NODE:
5078 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005079 case XML_ELEMENT_NODE:
5080 /*
5081 * Allocate a new node and minimally fills in
5082 * what's required
5083 */
5084 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5085 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005086 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005087 xmlFreeNodeList(repl);
5088 ret = -1;
5089 goto done;
5090 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005091 tmp->type = cur->type;
5092 tmp->name = cur->name;
5093 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005094 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005095 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005096 if (repl == NULL)
5097 repl = last = tmp;
5098 else {
5099 last->next = tmp;
5100 last = tmp;
5101 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005102 if (cur->type == XML_CDATA_SECTION_NODE) {
5103 /*
5104 * E59 spaces in CDATA does not match the
5105 * nonterminal S
5106 */
5107 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5108 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005109 break;
5110 default:
5111 break;
5112 }
5113 /*
5114 * Switch to next element
5115 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005116 cur = cur->next;
5117 while (cur == NULL) {
5118 cur = nodeVPop(ctxt);
5119 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005120 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005121 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005122 }
5123 }
5124
5125 /*
5126 * Relaunch the validation
5127 */
5128 ctxt->vstate = &ctxt->vstateTab[0];
5129 ctxt->vstateNr = 1;
5130 CONT = cont;
5131 NODE = repl;
5132 DEPTH = 0;
5133 OCCURS = 0;
5134 STATE = 0;
5135 ret = xmlValidateElementType(ctxt);
5136 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005137#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005138 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005139 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5140 char expr[5000];
5141 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005142
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005143 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005144 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005145 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005146#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005147 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005148 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005149 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005150#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005151 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005152
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005153 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005154 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5155 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5156 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005157 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005158 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5159 "Element content does not follow the DTD, expecting %s, got %s\n",
5160 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005161 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005162 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005163 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005164 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005165 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005166 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005167 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005168 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5169 "Element content does not follow the DTD\n",
5170 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005171 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005172 }
5173 ret = 0;
5174 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005175 if (ret == -3)
5176 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005177
Daniel Veillard23e73572002-09-19 19:56:43 +00005178#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005179done:
5180 /*
5181 * Deallocate the copy if done, and free up the validation stack
5182 */
5183 while (repl != NULL) {
5184 tmp = repl->next;
5185 xmlFree(repl);
5186 repl = tmp;
5187 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005188 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005189 if (ctxt->vstateTab != NULL) {
5190 xmlFree(ctxt->vstateTab);
5191 ctxt->vstateTab = NULL;
5192 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005193#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005194 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005195 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005196 if (ctxt->nodeTab != NULL) {
5197 xmlFree(ctxt->nodeTab);
5198 ctxt->nodeTab = NULL;
5199 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005200 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005201
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005202}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005203
Owen Taylor3473f882001-02-23 17:55:21 +00005204/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005205 * xmlValidateCdataElement:
5206 * @ctxt: the validation context
5207 * @doc: a document instance
5208 * @elem: an element instance
5209 *
5210 * Check that an element follows #CDATA
5211 *
5212 * returns 1 if valid or 0 otherwise
5213 */
5214static int
5215xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5216 xmlNodePtr elem) {
5217 int ret = 1;
5218 xmlNodePtr cur, child;
5219
Daniel Veillardceb09b92002-10-04 11:46:37 +00005220 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005221 return(0);
5222
5223 child = elem->children;
5224
5225 cur = child;
5226 while (cur != NULL) {
5227 switch (cur->type) {
5228 case XML_ENTITY_REF_NODE:
5229 /*
5230 * Push the current node to be able to roll back
5231 * and process within the entity
5232 */
5233 if ((cur->children != NULL) &&
5234 (cur->children->children != NULL)) {
5235 nodeVPush(ctxt, cur);
5236 cur = cur->children->children;
5237 continue;
5238 }
5239 break;
5240 case XML_COMMENT_NODE:
5241 case XML_PI_NODE:
5242 case XML_TEXT_NODE:
5243 case XML_CDATA_SECTION_NODE:
5244 break;
5245 default:
5246 ret = 0;
5247 goto done;
5248 }
5249 /*
5250 * Switch to next element
5251 */
5252 cur = cur->next;
5253 while (cur == NULL) {
5254 cur = nodeVPop(ctxt);
5255 if (cur == NULL)
5256 break;
5257 cur = cur->next;
5258 }
5259 }
5260done:
5261 ctxt->nodeMax = 0;
5262 ctxt->nodeNr = 0;
5263 if (ctxt->nodeTab != NULL) {
5264 xmlFree(ctxt->nodeTab);
5265 ctxt->nodeTab = NULL;
5266 }
5267 return(ret);
5268}
5269
5270/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005271 * xmlValidateCheckMixed:
5272 * @ctxt: the validation context
5273 * @cont: the mixed content model
5274 * @qname: the qualified name as appearing in the serialization
5275 *
5276 * Check if the given node is part of the content model.
5277 *
5278 * Returns 1 if yes, 0 if no, -1 in case of error
5279 */
5280static int
William M. Brackedb65a72004-02-06 07:36:04 +00005281xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005282 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005283 const xmlChar *name;
5284 int plen;
5285 name = xmlSplitQName3(qname, &plen);
5286
5287 if (name == NULL) {
5288 while (cont != NULL) {
5289 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5290 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5291 return(1);
5292 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5293 (cont->c1 != NULL) &&
5294 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5295 if ((cont->c1->prefix == NULL) &&
5296 (xmlStrEqual(cont->c1->name, qname)))
5297 return(1);
5298 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5299 (cont->c1 == NULL) ||
5300 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005301 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5302 "Internal: MIXED struct corrupted\n",
5303 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005304 break;
5305 }
5306 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005307 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005308 } else {
5309 while (cont != NULL) {
5310 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5311 if ((cont->prefix != NULL) &&
5312 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5313 (xmlStrEqual(cont->name, name)))
5314 return(1);
5315 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5316 (cont->c1 != NULL) &&
5317 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5318 if ((cont->c1->prefix != NULL) &&
5319 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5320 (xmlStrEqual(cont->c1->name, name)))
5321 return(1);
5322 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5323 (cont->c1 == NULL) ||
5324 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005325 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5326 "Internal: MIXED struct corrupted\n",
5327 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005328 break;
5329 }
5330 cont = cont->c2;
5331 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005332 }
5333 return(0);
5334}
5335
5336/**
5337 * xmlValidGetElemDecl:
5338 * @ctxt: the validation context
5339 * @doc: a document instance
5340 * @elem: an element instance
5341 * @extsubset: pointer, (out) indicate if the declaration was found
5342 * in the external subset.
5343 *
5344 * Finds a declaration associated to an element in the document.
5345 *
5346 * returns the pointer to the declaration or NULL if not found.
5347 */
5348static xmlElementPtr
5349xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5350 xmlNodePtr elem, int *extsubset) {
5351 xmlElementPtr elemDecl = NULL;
5352 const xmlChar *prefix = NULL;
5353
5354 if ((elem == NULL) || (elem->name == NULL)) return(NULL);
5355 if (extsubset != NULL)
5356 *extsubset = 0;
5357
5358 /*
5359 * Fetch the declaration for the qualified name
5360 */
5361 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5362 prefix = elem->ns->prefix;
5363
5364 if (prefix != NULL) {
5365 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5366 elem->name, prefix);
5367 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5368 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5369 elem->name, prefix);
5370 if ((elemDecl != NULL) && (extsubset != NULL))
5371 *extsubset = 1;
5372 }
5373 }
5374
5375 /*
5376 * Fetch the declaration for the non qualified name
5377 * This is "non-strict" validation should be done on the
5378 * full QName but in that case being flexible makes sense.
5379 */
5380 if (elemDecl == NULL) {
5381 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5382 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5383 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5384 if ((elemDecl != NULL) && (extsubset != NULL))
5385 *extsubset = 1;
5386 }
5387 }
5388 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005389 xmlErrValidNode(ctxt, elem,
5390 XML_DTD_UNKNOWN_ELEM,
5391 "No declaration for element %s\n",
5392 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005393 }
5394 return(elemDecl);
5395}
5396
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005397#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005398/**
5399 * xmlValidatePushElement:
5400 * @ctxt: the validation context
5401 * @doc: a document instance
5402 * @elem: an element instance
5403 * @qname: the qualified name as appearing in the serialization
5404 *
5405 * Push a new element start on the validation stack.
5406 *
5407 * returns 1 if no validation problem was found or 0 otherwise
5408 */
5409int
5410xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5411 xmlNodePtr elem, const xmlChar *qname) {
5412 int ret = 1;
5413 xmlElementPtr eDecl;
5414 int extsubset = 0;
5415
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005416/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005417 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5418 xmlValidStatePtr state = ctxt->vstate;
5419 xmlElementPtr elemDecl;
5420
5421 /*
5422 * Check the new element agaisnt the content model of the new elem.
5423 */
5424 if (state->elemDecl != NULL) {
5425 elemDecl = state->elemDecl;
5426
5427 switch(elemDecl->etype) {
5428 case XML_ELEMENT_TYPE_UNDEFINED:
5429 ret = 0;
5430 break;
5431 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005432 xmlErrValidNode(ctxt, state->node,
5433 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005434 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005435 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005436 ret = 0;
5437 break;
5438 case XML_ELEMENT_TYPE_ANY:
5439 /* I don't think anything is required then */
5440 break;
5441 case XML_ELEMENT_TYPE_MIXED:
5442 /* simple case of declared as #PCDATA */
5443 if ((elemDecl->content != NULL) &&
5444 (elemDecl->content->type ==
5445 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005446 xmlErrValidNode(ctxt, state->node,
5447 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005448 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005449 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005450 ret = 0;
5451 } else {
5452 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5453 qname);
5454 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005455 xmlErrValidNode(ctxt, state->node,
5456 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005457 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005458 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005459 }
5460 }
5461 break;
5462 case XML_ELEMENT_TYPE_ELEMENT:
5463 /*
5464 * TODO:
5465 * VC: Standalone Document Declaration
5466 * - element types with element content, if white space
5467 * occurs directly within any instance of those types.
5468 */
5469 if (state->exec != NULL) {
5470 ret = xmlRegExecPushString(state->exec, qname, NULL);
5471 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005472 xmlErrValidNode(ctxt, state->node,
5473 XML_DTD_CONTENT_MODEL,
5474 "Element %s content does not follow the DTD, Misplaced %s\n",
5475 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005476 ret = 0;
5477 } else {
5478 ret = 1;
5479 }
5480 }
5481 break;
5482 }
5483 }
5484 }
5485 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5486 vstateVPush(ctxt, eDecl, elem);
5487 return(ret);
5488}
5489
5490/**
5491 * xmlValidatePushCData:
5492 * @ctxt: the validation context
5493 * @data: some character data read
5494 * @len: the lenght of the data
5495 *
5496 * check the CData parsed for validation in the current stack
5497 *
5498 * returns 1 if no validation problem was found or 0 otherwise
5499 */
5500int
5501xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5502 int ret = 1;
5503
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005504/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005505 if (len <= 0)
5506 return(ret);
5507 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5508 xmlValidStatePtr state = ctxt->vstate;
5509 xmlElementPtr elemDecl;
5510
5511 /*
5512 * Check the new element agaisnt the content model of the new elem.
5513 */
5514 if (state->elemDecl != NULL) {
5515 elemDecl = state->elemDecl;
5516
5517 switch(elemDecl->etype) {
5518 case XML_ELEMENT_TYPE_UNDEFINED:
5519 ret = 0;
5520 break;
5521 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005522 xmlErrValidNode(ctxt, state->node,
5523 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005524 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005525 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005526 ret = 0;
5527 break;
5528 case XML_ELEMENT_TYPE_ANY:
5529 break;
5530 case XML_ELEMENT_TYPE_MIXED:
5531 break;
5532 case XML_ELEMENT_TYPE_ELEMENT:
5533 if (len > 0) {
5534 int i;
5535
5536 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005537 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005538 xmlErrValidNode(ctxt, state->node,
5539 XML_DTD_CONTENT_MODEL,
5540 "Element %s content does not follow the DTD, Text not allowed\n",
5541 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005542 ret = 0;
5543 goto done;
5544 }
5545 }
5546 /*
5547 * TODO:
5548 * VC: Standalone Document Declaration
5549 * element types with element content, if white space
5550 * occurs directly within any instance of those types.
5551 */
5552 }
5553 break;
5554 }
5555 }
5556 }
5557done:
5558 return(ret);
5559}
5560
5561/**
5562 * xmlValidatePopElement:
5563 * @ctxt: the validation context
5564 * @doc: a document instance
5565 * @elem: an element instance
5566 * @qname: the qualified name as appearing in the serialization
5567 *
5568 * Pop the element end from the validation stack.
5569 *
5570 * returns 1 if no validation problem was found or 0 otherwise
5571 */
5572int
5573xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005574 xmlNodePtr elem ATTRIBUTE_UNUSED,
5575 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005576 int ret = 1;
5577
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005578/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005579 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5580 xmlValidStatePtr state = ctxt->vstate;
5581 xmlElementPtr elemDecl;
5582
5583 /*
5584 * Check the new element agaisnt the content model of the new elem.
5585 */
5586 if (state->elemDecl != NULL) {
5587 elemDecl = state->elemDecl;
5588
5589 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5590 if (state->exec != NULL) {
5591 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5592 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005593 xmlErrValidNode(ctxt, state->node,
5594 XML_DTD_CONTENT_MODEL,
5595 "Element %s content does not follow the DTD, Expecting more child\n",
5596 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005597 } else {
5598 /*
5599 * previous validation errors should not generate
5600 * a new one here
5601 */
5602 ret = 1;
5603 }
5604 }
5605 }
5606 }
5607 vstateVPop(ctxt);
5608 }
5609 return(ret);
5610}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005611#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005612
5613/**
Owen Taylor3473f882001-02-23 17:55:21 +00005614 * xmlValidateOneElement:
5615 * @ctxt: the validation context
5616 * @doc: a document instance
5617 * @elem: an element instance
5618 *
5619 * Try to validate a single element and it's attributes,
5620 * basically it does the following checks as described by the
5621 * XML-1.0 recommendation:
5622 * - [ VC: Element Valid ]
5623 * - [ VC: Required Attribute ]
5624 * Then call xmlValidateOneAttribute() for each attribute present.
5625 *
5626 * The ID/IDREF checkings are done separately
5627 *
5628 * returns 1 if valid or 0 otherwise
5629 */
5630
5631int
5632xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5633 xmlNodePtr elem) {
5634 xmlElementPtr elemDecl = NULL;
5635 xmlElementContentPtr cont;
5636 xmlAttributePtr attr;
5637 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005638 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005639 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005640 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005641
5642 CHECK_DTD;
5643
5644 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005645 switch (elem->type) {
5646 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005647 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5648 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005649 return(0);
5650 case XML_TEXT_NODE:
5651 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005652 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5653 "Text element has children !\n",
5654 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005655 return(0);
5656 }
5657 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005658 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5659 "Text element has attribute !\n",
5660 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005661 return(0);
5662 }
5663 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005664 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5665 "Text element has namespace !\n",
5666 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005667 return(0);
5668 }
5669 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005670 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5671 "Text element has namespace !\n",
5672 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005673 return(0);
5674 }
5675 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005676 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5677 "Text element has no content !\n",
5678 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005679 return(0);
5680 }
5681 return(1);
5682 case XML_XINCLUDE_START:
5683 case XML_XINCLUDE_END:
5684 return(1);
5685 case XML_CDATA_SECTION_NODE:
5686 case XML_ENTITY_REF_NODE:
5687 case XML_PI_NODE:
5688 case XML_COMMENT_NODE:
5689 return(1);
5690 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005691 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5692 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005693 return(0);
5694 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005695 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5696 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005697 return(0);
5698 case XML_DOCUMENT_NODE:
5699 case XML_DOCUMENT_TYPE_NODE:
5700 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005701 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5702 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005703 return(0);
5704 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005705 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5706 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005707 return(0);
5708 case XML_ELEMENT_NODE:
5709 break;
5710 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005711 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5712 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005713 return(0);
5714 }
Owen Taylor3473f882001-02-23 17:55:21 +00005715
5716 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005717 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005718 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005719 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5720 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005721 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005722
Daniel Veillardea7751d2002-12-20 00:16:24 +00005723 /*
5724 * If vstateNr is not zero that means continuous validation is
5725 * activated, do not try to check the content model at that level.
5726 */
5727 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005728 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005729 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005730 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005731 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5732 "No declaration for element %s\n",
5733 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005734 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005735 case XML_ELEMENT_TYPE_EMPTY:
5736 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005737 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005738 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005739 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005740 ret = 0;
5741 }
5742 break;
5743 case XML_ELEMENT_TYPE_ANY:
5744 /* I don't think anything is required then */
5745 break;
5746 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005747
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005748 /* simple case of declared as #PCDATA */
5749 if ((elemDecl->content != NULL) &&
5750 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5751 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5752 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005753 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005754 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005755 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005756 }
5757 break;
5758 }
Owen Taylor3473f882001-02-23 17:55:21 +00005759 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005760 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005761 while (child != NULL) {
5762 if (child->type == XML_ELEMENT_NODE) {
5763 name = child->name;
5764 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005765 xmlChar fn[50];
5766 xmlChar *fullname;
5767
5768 fullname = xmlBuildQName(child->name, child->ns->prefix,
5769 fn, 50);
5770 if (fullname == NULL)
5771 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005772 cont = elemDecl->content;
5773 while (cont != NULL) {
5774 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005775 if (xmlStrEqual(cont->name, fullname))
5776 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005777 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5778 (cont->c1 != NULL) &&
5779 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005780 if (xmlStrEqual(cont->c1->name, fullname))
5781 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005782 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5783 (cont->c1 == NULL) ||
5784 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005785 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5786 "Internal: MIXED struct corrupted\n",
5787 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005788 break;
5789 }
5790 cont = cont->c2;
5791 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005792 if ((fullname != fn) && (fullname != child->name))
5793 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005794 if (cont != NULL)
5795 goto child_ok;
5796 }
5797 cont = elemDecl->content;
5798 while (cont != NULL) {
5799 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5800 if (xmlStrEqual(cont->name, name)) break;
5801 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5802 (cont->c1 != NULL) &&
5803 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5804 if (xmlStrEqual(cont->c1->name, name)) break;
5805 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5806 (cont->c1 == NULL) ||
5807 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005808 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5809 "Internal: MIXED struct corrupted\n",
5810 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005811 break;
5812 }
5813 cont = cont->c2;
5814 }
5815 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005816 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00005817 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005818 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005819 ret = 0;
5820 }
5821 }
5822child_ok:
5823 child = child->next;
5824 }
5825 break;
5826 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005827 if ((doc->standalone == 1) && (extsubset == 1)) {
5828 /*
5829 * VC: Standalone Document Declaration
5830 * - element types with element content, if white space
5831 * occurs directly within any instance of those types.
5832 */
5833 child = elem->children;
5834 while (child != NULL) {
5835 if (child->type == XML_TEXT_NODE) {
5836 const xmlChar *content = child->content;
5837
William M. Brack76e95df2003-10-18 16:20:14 +00005838 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005839 content++;
5840 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005841 xmlErrValidNode(ctxt, elem,
5842 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005843"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005844 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005845 ret = 0;
5846 break;
5847 }
5848 }
5849 child =child->next;
5850 }
5851 }
Owen Taylor3473f882001-02-23 17:55:21 +00005852 child = elem->children;
5853 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005854 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005855 if (tmp <= 0)
5856 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005857 break;
5858 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005859 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00005860
5861 /* [ VC: Required Attribute ] */
5862 attr = elemDecl->attributes;
5863 while (attr != NULL) {
5864 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005865 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005866
Daniel Veillarde4301c82002-02-13 13:32:35 +00005867 if ((attr->prefix == NULL) &&
5868 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5869 xmlNsPtr ns;
5870
5871 ns = elem->nsDef;
5872 while (ns != NULL) {
5873 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005874 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005875 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00005876 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005877 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5878 xmlNsPtr ns;
5879
5880 ns = elem->nsDef;
5881 while (ns != NULL) {
5882 if (xmlStrEqual(attr->name, ns->prefix))
5883 goto found;
5884 ns = ns->next;
5885 }
5886 } else {
5887 xmlAttrPtr attrib;
5888
5889 attrib = elem->properties;
5890 while (attrib != NULL) {
5891 if (xmlStrEqual(attrib->name, attr->name)) {
5892 if (attr->prefix != NULL) {
5893 xmlNsPtr nameSpace = attrib->ns;
5894
5895 if (nameSpace == NULL)
5896 nameSpace = elem->ns;
5897 /*
5898 * qualified names handling is problematic, having a
5899 * different prefix should be possible but DTDs don't
5900 * allow to define the URI instead of the prefix :-(
5901 */
5902 if (nameSpace == NULL) {
5903 if (qualified < 0)
5904 qualified = 0;
5905 } else if (!xmlStrEqual(nameSpace->prefix,
5906 attr->prefix)) {
5907 if (qualified < 1)
5908 qualified = 1;
5909 } else
5910 goto found;
5911 } else {
5912 /*
5913 * We should allow applications to define namespaces
5914 * for their application even if the DTD doesn't
5915 * carry one, otherwise, basically we would always
5916 * break.
5917 */
5918 goto found;
5919 }
5920 }
5921 attrib = attrib->next;
5922 }
Owen Taylor3473f882001-02-23 17:55:21 +00005923 }
5924 if (qualified == -1) {
5925 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005926 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005927 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005928 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005929 ret = 0;
5930 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005931 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005932 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005933 elem->name, attr->prefix,attr->name);
5934 ret = 0;
5935 }
5936 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005937 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005938 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005939 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005940 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005941 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005942 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005943 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005944 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005945 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5946 /*
5947 * Special tests checking #FIXED namespace declarations
5948 * have the right value since this is not done as an
5949 * attribute checking
5950 */
5951 if ((attr->prefix == NULL) &&
5952 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5953 xmlNsPtr ns;
5954
5955 ns = elem->nsDef;
5956 while (ns != NULL) {
5957 if (ns->prefix == NULL) {
5958 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005959 xmlErrValidNode(ctxt, elem,
5960 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00005961 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005962 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005963 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005964 }
5965 goto found;
5966 }
5967 ns = ns->next;
5968 }
5969 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5970 xmlNsPtr ns;
5971
5972 ns = elem->nsDef;
5973 while (ns != NULL) {
5974 if (xmlStrEqual(attr->name, ns->prefix)) {
5975 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005976 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005977 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005978 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005979 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005980 }
5981 goto found;
5982 }
5983 ns = ns->next;
5984 }
5985 }
Owen Taylor3473f882001-02-23 17:55:21 +00005986 }
5987found:
5988 attr = attr->nexth;
5989 }
5990 return(ret);
5991}
5992
5993/**
5994 * xmlValidateRoot:
5995 * @ctxt: the validation context
5996 * @doc: a document instance
5997 *
5998 * Try to validate a the root element
5999 * basically it does the following check as described by the
6000 * XML-1.0 recommendation:
6001 * - [ VC: Root Element Type ]
6002 * it doesn't try to recurse or apply other check to the element
6003 *
6004 * returns 1 if valid or 0 otherwise
6005 */
6006
6007int
6008xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6009 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006010 int ret;
6011
Owen Taylor3473f882001-02-23 17:55:21 +00006012 if (doc == NULL) return(0);
6013
6014 root = xmlDocGetRootElement(doc);
6015 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006016 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6017 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006018 return(0);
6019 }
6020
6021 /*
6022 * When doing post validation against a separate DTD, those may
6023 * no internal subset has been generated
6024 */
6025 if ((doc->intSubset != NULL) &&
6026 (doc->intSubset->name != NULL)) {
6027 /*
6028 * Check first the document root against the NQName
6029 */
6030 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6031 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006032 xmlChar fn[50];
6033 xmlChar *fullname;
6034
6035 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6036 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006037 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006038 return(0);
6039 }
6040 ret = xmlStrEqual(doc->intSubset->name, fullname);
6041 if ((fullname != fn) && (fullname != root->name))
6042 xmlFree(fullname);
6043 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006044 goto name_ok;
6045 }
6046 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6047 (xmlStrEqual(root->name, BAD_CAST "html")))
6048 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006049 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6050 "root and DTD name do not match '%s' and '%s'\n",
6051 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006052 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006053 }
6054 }
6055name_ok:
6056 return(1);
6057}
6058
6059
6060/**
6061 * xmlValidateElement:
6062 * @ctxt: the validation context
6063 * @doc: a document instance
6064 * @elem: an element instance
6065 *
6066 * Try to validate the subtree under an element
6067 *
6068 * returns 1 if valid or 0 otherwise
6069 */
6070
6071int
6072xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6073 xmlNodePtr child;
6074 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006075 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006076 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006077 int ret = 1;
6078
6079 if (elem == NULL) return(0);
6080
6081 /*
6082 * XInclude elements were added after parsing in the infoset,
6083 * they don't really mean anything validation wise.
6084 */
6085 if ((elem->type == XML_XINCLUDE_START) ||
6086 (elem->type == XML_XINCLUDE_END))
6087 return(1);
6088
6089 CHECK_DTD;
6090
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006091 /*
6092 * Entities references have to be handled separately
6093 */
6094 if (elem->type == XML_ENTITY_REF_NODE) {
6095 return(1);
6096 }
6097
Owen Taylor3473f882001-02-23 17:55:21 +00006098 ret &= xmlValidateOneElement(ctxt, doc, elem);
6099 attr = elem->properties;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006100 while (attr != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006101 value = xmlNodeListGetString(doc, attr->children, 0);
6102 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6103 if (value != NULL)
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006104 xmlFree((char *)value);
Owen Taylor3473f882001-02-23 17:55:21 +00006105 attr= attr->next;
6106 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006107 ns = elem->nsDef;
6108 while (ns != NULL) {
Daniel Veillard1f5c9892003-12-29 17:09:55 +00006109 if (elem->ns == NULL)
6110 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6111 ns, ns->href);
6112 else
6113 ret &= xmlValidateOneNamespace(ctxt, doc, elem, elem->ns->prefix,
6114 ns, ns->href);
Daniel Veillarde133dd82003-10-30 10:42:20 +00006115 ns = ns->next;
6116 }
Owen Taylor3473f882001-02-23 17:55:21 +00006117 child = elem->children;
6118 while (child != NULL) {
6119 ret &= xmlValidateElement(ctxt, doc, child);
6120 child = child->next;
6121 }
6122
6123 return(ret);
6124}
6125
Daniel Veillard8730c562001-02-26 10:49:57 +00006126/**
6127 * xmlValidateRef:
6128 * @ref: A reference to be validated
6129 * @ctxt: Validation context
6130 * @name: Name of ID we are searching for
6131 *
6132 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006133static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006134xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006135 const xmlChar *name) {
6136 xmlAttrPtr id;
6137 xmlAttrPtr attr;
6138
6139 if (ref == NULL)
6140 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006141 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006142 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006143 attr = ref->attr;
6144 if (attr == NULL) {
6145 xmlChar *dup, *str = NULL, *cur, save;
6146
6147 dup = xmlStrdup(name);
6148 if (dup == NULL) {
6149 ctxt->valid = 0;
6150 return;
6151 }
6152 cur = dup;
6153 while (*cur != 0) {
6154 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006155 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006156 save = *cur;
6157 *cur = 0;
6158 id = xmlGetID(ctxt->doc, str);
6159 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006160 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006161 "attribute %s line %d references an unknown ID \"%s\"\n",
6162 ref->name, ref->lineno, str);
6163 ctxt->valid = 0;
6164 }
6165 if (save == 0)
6166 break;
6167 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006168 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006169 }
6170 xmlFree(dup);
6171 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006172 id = xmlGetID(ctxt->doc, name);
6173 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006174 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006175 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006176 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006177 ctxt->valid = 0;
6178 }
6179 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6180 xmlChar *dup, *str = NULL, *cur, save;
6181
6182 dup = xmlStrdup(name);
6183 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006184 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006185 ctxt->valid = 0;
6186 return;
6187 }
6188 cur = dup;
6189 while (*cur != 0) {
6190 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006191 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006192 save = *cur;
6193 *cur = 0;
6194 id = xmlGetID(ctxt->doc, str);
6195 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006196 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006197 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006198 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006199 ctxt->valid = 0;
6200 }
6201 if (save == 0)
6202 break;
6203 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006204 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006205 }
6206 xmlFree(dup);
6207 }
6208}
6209
6210/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006211 * xmlWalkValidateList:
6212 * @data: Contents of current link
6213 * @user: Value supplied by the user
6214 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006215 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006216 */
6217static int
6218xmlWalkValidateList(const void *data, const void *user)
6219{
6220 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6221 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6222 return 1;
6223}
6224
6225/**
6226 * xmlValidateCheckRefCallback:
6227 * @ref_list: List of references
6228 * @ctxt: Validation context
6229 * @name: Name of ID we are searching for
6230 *
6231 */
6232static void
6233xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6234 const xmlChar *name) {
6235 xmlValidateMemo memo;
6236
6237 if (ref_list == NULL)
6238 return;
6239 memo.ctxt = ctxt;
6240 memo.name = name;
6241
6242 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6243
6244}
6245
6246/**
Owen Taylor3473f882001-02-23 17:55:21 +00006247 * xmlValidateDocumentFinal:
6248 * @ctxt: the validation context
6249 * @doc: a document instance
6250 *
6251 * Does the final step for the document validation once all the
6252 * incremental validation steps have been completed
6253 *
6254 * basically it does the following checks described by the XML Rec
6255 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006256 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006257 *
6258 * returns 1 if valid or 0 otherwise
6259 */
6260
6261int
6262xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6263 xmlRefTablePtr table;
6264
6265 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006266 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6267 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006268 return(0);
6269 }
6270
6271 /*
6272 * Check all the NOTATION/NOTATIONS attributes
6273 */
6274 /*
6275 * Check all the ENTITY/ENTITIES attributes definition for validity
6276 */
6277 /*
6278 * Check all the IDREF/IDREFS attributes definition for validity
6279 */
6280 table = (xmlRefTablePtr) doc->refs;
6281 ctxt->doc = doc;
6282 ctxt->valid = 1;
6283 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6284 return(ctxt->valid);
6285}
6286
6287/**
6288 * xmlValidateDtd:
6289 * @ctxt: the validation context
6290 * @doc: a document instance
6291 * @dtd: a dtd instance
6292 *
6293 * Try to validate the document against the dtd instance
6294 *
6295 * basically it does check all the definitions in the DtD.
6296 *
6297 * returns 1 if valid or 0 otherwise
6298 */
6299
6300int
6301xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6302 int ret;
6303 xmlDtdPtr oldExt;
6304 xmlNodePtr root;
6305
6306 if (dtd == NULL) return(0);
6307 if (doc == NULL) return(0);
6308 oldExt = doc->extSubset;
6309 doc->extSubset = dtd;
6310 ret = xmlValidateRoot(ctxt, doc);
6311 if (ret == 0) {
6312 doc->extSubset = oldExt;
6313 return(ret);
6314 }
6315 if (doc->ids != NULL) {
6316 xmlFreeIDTable(doc->ids);
6317 doc->ids = NULL;
6318 }
6319 if (doc->refs != NULL) {
6320 xmlFreeRefTable(doc->refs);
6321 doc->refs = NULL;
6322 }
6323 root = xmlDocGetRootElement(doc);
6324 ret = xmlValidateElement(ctxt, doc, root);
6325 ret &= xmlValidateDocumentFinal(ctxt, doc);
6326 doc->extSubset = oldExt;
6327 return(ret);
6328}
6329
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006330static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006331xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6332 const xmlChar *name ATTRIBUTE_UNUSED) {
6333 if (cur == NULL)
6334 return;
6335 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6336 xmlChar *notation = cur->content;
6337
Daniel Veillard878eab02002-02-19 13:46:09 +00006338 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006339 int ret;
6340
6341 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6342 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006343 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006344 }
6345 }
6346 }
6347}
6348
6349static void
Owen Taylor3473f882001-02-23 17:55:21 +00006350xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006351 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006352 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006353 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006354 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006355
Owen Taylor3473f882001-02-23 17:55:21 +00006356 if (cur == NULL)
6357 return;
6358 switch (cur->atype) {
6359 case XML_ATTRIBUTE_CDATA:
6360 case XML_ATTRIBUTE_ID:
6361 case XML_ATTRIBUTE_IDREF :
6362 case XML_ATTRIBUTE_IDREFS:
6363 case XML_ATTRIBUTE_NMTOKEN:
6364 case XML_ATTRIBUTE_NMTOKENS:
6365 case XML_ATTRIBUTE_ENUMERATION:
6366 break;
6367 case XML_ATTRIBUTE_ENTITY:
6368 case XML_ATTRIBUTE_ENTITIES:
6369 case XML_ATTRIBUTE_NOTATION:
6370 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006371
6372 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6373 cur->atype, cur->defaultValue);
6374 if ((ret == 0) && (ctxt->valid == 1))
6375 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006376 }
6377 if (cur->tree != NULL) {
6378 xmlEnumerationPtr tree = cur->tree;
6379 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006380 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006381 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006382 if ((ret == 0) && (ctxt->valid == 1))
6383 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006384 tree = tree->next;
6385 }
6386 }
6387 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006388 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6389 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006390 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006391 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006392 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006393 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006394 return;
6395 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006396
6397 if (doc != NULL)
6398 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6399 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006400 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006401 if ((elem == NULL) && (cur->parent != NULL) &&
6402 (cur->parent->type == XML_DTD_NODE))
6403 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006404 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006405 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006406 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006407 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006408 return;
6409 }
6410 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006411 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006412 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006413 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006414 ctxt->valid = 0;
6415 }
6416 }
Owen Taylor3473f882001-02-23 17:55:21 +00006417}
6418
6419/**
6420 * xmlValidateDtdFinal:
6421 * @ctxt: the validation context
6422 * @doc: a document instance
6423 *
6424 * Does the final step for the dtds validation once all the
6425 * subsets have been parsed
6426 *
6427 * basically it does the following checks described by the XML Rec
6428 * - check that ENTITY and ENTITIES type attributes default or
6429 * possible values matches one of the defined entities.
6430 * - check that NOTATION type attributes default or
6431 * possible values matches one of the defined notations.
6432 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006433 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006434 */
6435
6436int
6437xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006438 xmlDtdPtr dtd;
6439 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006440 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006441
6442 if (doc == NULL) return(0);
6443 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6444 return(0);
6445 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006446 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006447 dtd = doc->intSubset;
6448 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6449 table = (xmlAttributeTablePtr) dtd->attributes;
6450 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006451 }
6452 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006453 entities = (xmlEntitiesTablePtr) dtd->entities;
6454 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6455 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006456 }
6457 dtd = doc->extSubset;
6458 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6459 table = (xmlAttributeTablePtr) dtd->attributes;
6460 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006461 }
6462 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006463 entities = (xmlEntitiesTablePtr) dtd->entities;
6464 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6465 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006466 }
6467 return(ctxt->valid);
6468}
6469
6470/**
6471 * xmlValidateDocument:
6472 * @ctxt: the validation context
6473 * @doc: a document instance
6474 *
6475 * Try to validate the document instance
6476 *
6477 * basically it does the all the checks described by the XML Rec
6478 * i.e. validates the internal and external subset (if present)
6479 * and validate the document tree.
6480 *
6481 * returns 1 if valid or 0 otherwise
6482 */
6483
6484int
6485xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6486 int ret;
6487 xmlNodePtr root;
6488
Daniel Veillard2fd85422002-10-16 14:32:41 +00006489 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006490 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6491 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006492 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006493 }
Owen Taylor3473f882001-02-23 17:55:21 +00006494 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6495 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6496 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6497 doc->intSubset->SystemID);
6498 if (doc->extSubset == NULL) {
6499 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006500 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006501 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006502 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006503 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006504 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006505 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006506 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006507 }
6508 return(0);
6509 }
6510 }
6511
6512 if (doc->ids != NULL) {
6513 xmlFreeIDTable(doc->ids);
6514 doc->ids = NULL;
6515 }
6516 if (doc->refs != NULL) {
6517 xmlFreeRefTable(doc->refs);
6518 doc->refs = NULL;
6519 }
6520 ret = xmlValidateDtdFinal(ctxt, doc);
6521 if (!xmlValidateRoot(ctxt, doc)) return(0);
6522
6523 root = xmlDocGetRootElement(doc);
6524 ret &= xmlValidateElement(ctxt, doc, root);
6525 ret &= xmlValidateDocumentFinal(ctxt, doc);
6526 return(ret);
6527}
6528
Owen Taylor3473f882001-02-23 17:55:21 +00006529/************************************************************************
6530 * *
6531 * Routines for dynamic validation editing *
6532 * *
6533 ************************************************************************/
6534
6535/**
6536 * xmlValidGetPotentialChildren:
6537 * @ctree: an element content tree
6538 * @list: an array to store the list of child names
6539 * @len: a pointer to the number of element in the list
6540 * @max: the size of the array
6541 *
6542 * Build/extend a list of potential children allowed by the content tree
6543 *
6544 * returns the number of element in the list, or -1 in case of error.
6545 */
6546
6547int
6548xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6549 int *len, int max) {
6550 int i;
6551
6552 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6553 return(-1);
6554 if (*len >= max) return(*len);
6555
6556 switch (ctree->type) {
6557 case XML_ELEMENT_CONTENT_PCDATA:
6558 for (i = 0; i < *len;i++)
6559 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6560 list[(*len)++] = BAD_CAST "#PCDATA";
6561 break;
6562 case XML_ELEMENT_CONTENT_ELEMENT:
6563 for (i = 0; i < *len;i++)
6564 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6565 list[(*len)++] = ctree->name;
6566 break;
6567 case XML_ELEMENT_CONTENT_SEQ:
6568 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6569 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6570 break;
6571 case XML_ELEMENT_CONTENT_OR:
6572 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6573 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6574 break;
6575 }
6576
6577 return(*len);
6578}
6579
6580/**
6581 * xmlValidGetValidElements:
6582 * @prev: an element to insert after
6583 * @next: an element to insert next
6584 * @list: an array to store the list of child names
6585 * @max: the size of the array
6586 *
6587 * This function returns the list of authorized children to insert
6588 * within an existing tree while respecting the validity constraints
6589 * forced by the Dtd. The insertion point is defined using @prev and
6590 * @next in the following ways:
6591 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6592 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6593 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6594 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6595 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6596 *
6597 * pointers to the element names are inserted at the beginning of the array
6598 * and do not need to be freed.
6599 *
6600 * returns the number of element in the list, or -1 in case of error. If
6601 * the function returns the value @max the caller is invited to grow the
6602 * receiving array and retry.
6603 */
6604
6605int
6606xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
6607 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006608 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006609 int nb_valid_elements = 0;
6610 const xmlChar *elements[256];
6611 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006612 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006613
6614 xmlNode *ref_node;
6615 xmlNode *parent;
6616 xmlNode *test_node;
6617
6618 xmlNode *prev_next;
6619 xmlNode *next_prev;
6620 xmlNode *parent_childs;
6621 xmlNode *parent_last;
6622
6623 xmlElement *element_desc;
6624
Daniel Veillardbb4e46d2002-03-10 16:49:08 +00006625 memset(&vctxt, 0, sizeof (xmlValidCtxt));
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006626
Owen Taylor3473f882001-02-23 17:55:21 +00006627 if (prev == NULL && next == NULL)
6628 return(-1);
6629
6630 if (list == NULL) return(-1);
6631 if (max <= 0) return(-1);
6632
6633 nb_valid_elements = 0;
6634 ref_node = prev ? prev : next;
6635 parent = ref_node->parent;
6636
6637 /*
6638 * Retrieves the parent element declaration
6639 */
6640 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6641 parent->name);
6642 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6643 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6644 parent->name);
6645 if (element_desc == NULL) return(-1);
6646
6647 /*
6648 * Do a backup of the current tree structure
6649 */
6650 prev_next = prev ? prev->next : NULL;
6651 next_prev = next ? next->prev : NULL;
6652 parent_childs = parent->children;
6653 parent_last = parent->last;
6654
6655 /*
6656 * Creates a dummy node and insert it into the tree
6657 */
6658 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
6659 test_node->doc = ref_node->doc;
6660 test_node->parent = parent;
6661 test_node->prev = prev;
6662 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006663 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006664
6665 if (prev) prev->next = test_node;
6666 else parent->children = test_node;
6667
6668 if (next) next->prev = test_node;
6669 else parent->last = test_node;
6670
6671 /*
6672 * Insert each potential child node and check if the parent is
6673 * still valid
6674 */
6675 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6676 elements, &nb_elements, 256);
6677
6678 for (i = 0;i < nb_elements;i++) {
6679 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006680 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006681 int j;
6682
6683 for (j = 0; j < nb_valid_elements;j++)
6684 if (xmlStrEqual(elements[i], list[j])) break;
6685 list[nb_valid_elements++] = elements[i];
6686 if (nb_valid_elements >= max) break;
6687 }
6688 }
6689
6690 /*
6691 * Restore the tree structure
6692 */
6693 if (prev) prev->next = prev_next;
6694 if (next) next->prev = next_prev;
6695 parent->children = parent_childs;
6696 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006697
6698 /*
6699 * Free up the dummy node
6700 */
6701 test_node->name = name;
6702 xmlFreeNode(test_node);
6703
Owen Taylor3473f882001-02-23 17:55:21 +00006704 return(nb_valid_elements);
6705}
Daniel Veillard4432df22003-09-28 18:58:27 +00006706#endif /* LIBXML_VALID_ENABLED */
6707