blob: 33a2a9a80aeb27f7465333c4e975196a286e3e3a [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/**
2718 * xmlAddRef:
2719 * @ctxt: the validation context
2720 * @doc: pointer to the document
2721 * @value: the value name
2722 * @attr: the attribute holding the Ref
2723 *
2724 * Register a new ref declaration
2725 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002726 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002727 */
2728xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002729xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002730 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002731 xmlRefPtr ret;
2732 xmlRefTablePtr table;
2733 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002734
Daniel Veillard37721922001-05-04 15:21:12 +00002735 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002736 return(NULL);
2737 }
2738 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002739 return(NULL);
2740 }
2741 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002742 return(NULL);
2743 }
Owen Taylor3473f882001-02-23 17:55:21 +00002744
Daniel Veillard37721922001-05-04 15:21:12 +00002745 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002746 * Create the Ref table if needed.
2747 */
Daniel Veillard37721922001-05-04 15:21:12 +00002748 table = (xmlRefTablePtr) doc->refs;
2749 if (table == NULL)
2750 doc->refs = table = xmlCreateRefTable();
2751 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002752 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002753 "xmlAddRef: Table creation failed!\n");
2754 return(NULL);
2755 }
Owen Taylor3473f882001-02-23 17:55:21 +00002756
Daniel Veillard37721922001-05-04 15:21:12 +00002757 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2758 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002759 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002760 return(NULL);
2761 }
Owen Taylor3473f882001-02-23 17:55:21 +00002762
Daniel Veillard37721922001-05-04 15:21:12 +00002763 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002764 * fill the structure.
2765 */
Daniel Veillard37721922001-05-04 15:21:12 +00002766 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002767 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2768 /*
2769 * Operating in streaming mode, attr is gonna disapear
2770 */
2771 ret->name = xmlStrdup(attr->name);
2772 ret->attr = NULL;
2773 } else {
2774 ret->name = NULL;
2775 ret->attr = attr;
2776 }
2777 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002778
Daniel Veillard37721922001-05-04 15:21:12 +00002779 /* To add a reference :-
2780 * References are maintained as a list of references,
2781 * Lookup the entry, if no entry create new nodelist
2782 * Add the owning node to the NodeList
2783 * Return the ref
2784 */
Owen Taylor3473f882001-02-23 17:55:21 +00002785
Daniel Veillard37721922001-05-04 15:21:12 +00002786 if (NULL == (ref_list = xmlHashLookup(table, value))) {
2787 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, NULL))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002788 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2789 "xmlAddRef: Reference list creation failed!\n",
2790 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002791 return(NULL);
2792 }
2793 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2794 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002795 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2796 "xmlAddRef: Reference list insertion failed!\n",
2797 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002798 return(NULL);
2799 }
2800 }
Daniel Veillard965983a2004-02-17 16:30:24 +00002801/* xmlListInsert(ref_list, ret); */
2802 xmlListAppend(ref_list, ret);
Daniel Veillard37721922001-05-04 15:21:12 +00002803 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002804}
2805
2806/**
2807 * xmlFreeRefTable:
2808 * @table: An ref table
2809 *
2810 * Deallocate the memory used by an Ref hash table.
2811 */
2812void
2813xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002814 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002815}
2816
2817/**
2818 * xmlIsRef:
2819 * @doc: the document
2820 * @elem: the element carrying the attribute
2821 * @attr: the attribute
2822 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002823 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00002824 * then this is simple, otherwise we use an heuristic: name Ref (upper
2825 * or lowercase).
2826 *
2827 * Returns 0 or 1 depending on the lookup result
2828 */
2829int
2830xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002831 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2832 return(0);
2833 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2834 /* TODO @@@ */
2835 return(0);
2836 } else {
2837 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00002838
Daniel Veillard37721922001-05-04 15:21:12 +00002839 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2840 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2841 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2842 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002843
Daniel Veillard37721922001-05-04 15:21:12 +00002844 if ((attrDecl != NULL) &&
2845 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2846 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2847 return(1);
2848 }
2849 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002850}
2851
2852/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002853 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00002854 * @doc: the document
2855 * @attr: the attribute
2856 *
2857 * Remove the given attribute from the Ref table maintained internally.
2858 *
2859 * Returns -1 if the lookup failed and 0 otherwise
2860 */
2861int
2862xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002863 xmlListPtr ref_list;
2864 xmlRefTablePtr table;
2865 xmlChar *ID;
2866 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00002867
Daniel Veillard37721922001-05-04 15:21:12 +00002868 if (doc == NULL) return(-1);
2869 if (attr == NULL) return(-1);
2870 table = (xmlRefTablePtr) doc->refs;
2871 if (table == NULL)
2872 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002873
Daniel Veillard37721922001-05-04 15:21:12 +00002874 if (attr == NULL)
2875 return(-1);
2876 ID = xmlNodeListGetString(doc, attr->children, 1);
2877 if (ID == NULL)
2878 return(-1);
2879 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00002880
Daniel Veillard37721922001-05-04 15:21:12 +00002881 if(ref_list == NULL) {
2882 xmlFree(ID);
2883 return (-1);
2884 }
2885 /* At this point, ref_list refers to a list of references which
2886 * have the same key as the supplied attr. Our list of references
2887 * is ordered by reference address and we don't have that information
2888 * here to use when removing. We'll have to walk the list and
2889 * check for a matching attribute, when we find one stop the walk
2890 * and remove the entry.
2891 * The list is ordered by reference, so that means we don't have the
2892 * key. Passing the list and the reference to the walker means we
2893 * will have enough data to be able to remove the entry.
2894 */
2895 target.l = ref_list;
2896 target.ap = attr;
2897
2898 /* Remove the supplied attr from our list */
2899 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00002900
Daniel Veillard37721922001-05-04 15:21:12 +00002901 /*If the list is empty then remove the list entry in the hash */
2902 if (xmlListEmpty(ref_list))
2903 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2904 xmlFreeRefList);
2905 xmlFree(ID);
2906 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002907}
2908
2909/**
2910 * xmlGetRefs:
2911 * @doc: pointer to the document
2912 * @ID: the ID value
2913 *
2914 * Find the set of references for the supplied ID.
2915 *
2916 * Returns NULL if not found, otherwise node set for the ID.
2917 */
2918xmlListPtr
2919xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00002920 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00002921
Daniel Veillard37721922001-05-04 15:21:12 +00002922 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002923 return(NULL);
2924 }
Owen Taylor3473f882001-02-23 17:55:21 +00002925
Daniel Veillard37721922001-05-04 15:21:12 +00002926 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002927 return(NULL);
2928 }
Owen Taylor3473f882001-02-23 17:55:21 +00002929
Daniel Veillard37721922001-05-04 15:21:12 +00002930 table = (xmlRefTablePtr) doc->refs;
2931 if (table == NULL)
2932 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002933
Daniel Veillard37721922001-05-04 15:21:12 +00002934 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00002935}
2936
2937/************************************************************************
2938 * *
2939 * Routines for validity checking *
2940 * *
2941 ************************************************************************/
2942
2943/**
2944 * xmlGetDtdElementDesc:
2945 * @dtd: a pointer to the DtD to search
2946 * @name: the element name
2947 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002948 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002949 *
2950 * returns the xmlElementPtr if found or NULL
2951 */
2952
2953xmlElementPtr
2954xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2955 xmlElementTablePtr table;
2956 xmlElementPtr cur;
2957 xmlChar *uqname = NULL, *prefix = NULL;
2958
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002959 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002960 if (dtd->elements == NULL)
2961 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002962 table = (xmlElementTablePtr) dtd->elements;
2963
2964 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002965 if (uqname != NULL)
2966 name = uqname;
2967 cur = xmlHashLookup2(table, name, prefix);
2968 if (prefix != NULL) xmlFree(prefix);
2969 if (uqname != NULL) xmlFree(uqname);
2970 return(cur);
2971}
2972/**
2973 * xmlGetDtdElementDesc2:
2974 * @dtd: a pointer to the DtD to search
2975 * @name: the element name
2976 * @create: create an empty description if not found
2977 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002978 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00002979 *
2980 * returns the xmlElementPtr if found or NULL
2981 */
2982
Daniel Veillard86fd5a72001-12-13 14:55:21 +00002983static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00002984xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
2985 xmlElementTablePtr table;
2986 xmlElementPtr cur;
2987 xmlChar *uqname = NULL, *prefix = NULL;
2988
2989 if (dtd == NULL) return(NULL);
2990 if (dtd->elements == NULL) {
2991 if (!create)
2992 return(NULL);
2993 /*
2994 * Create the Element table if needed.
2995 */
2996 table = (xmlElementTablePtr) dtd->elements;
2997 if (table == NULL) {
2998 table = xmlCreateElementTable();
2999 dtd->elements = (void *) table;
3000 }
3001 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003002 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003003 return(NULL);
3004 }
3005 }
3006 table = (xmlElementTablePtr) dtd->elements;
3007
3008 uqname = xmlSplitQName2(name, &prefix);
3009 if (uqname != NULL)
3010 name = uqname;
3011 cur = xmlHashLookup2(table, name, prefix);
3012 if ((cur == NULL) && (create)) {
3013 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3014 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003015 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003016 return(NULL);
3017 }
3018 memset(cur, 0, sizeof(xmlElement));
3019 cur->type = XML_ELEMENT_DECL;
3020
3021 /*
3022 * fill the structure.
3023 */
3024 cur->name = xmlStrdup(name);
3025 cur->prefix = xmlStrdup(prefix);
3026 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3027
3028 xmlHashAddEntry2(table, name, prefix, cur);
3029 }
3030 if (prefix != NULL) xmlFree(prefix);
3031 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003032 return(cur);
3033}
3034
3035/**
3036 * xmlGetDtdQElementDesc:
3037 * @dtd: a pointer to the DtD to search
3038 * @name: the element name
3039 * @prefix: the element namespace prefix
3040 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003041 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003042 *
3043 * returns the xmlElementPtr if found or NULL
3044 */
3045
Daniel Veillard48da9102001-08-07 01:10:10 +00003046xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003047xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3048 const xmlChar *prefix) {
3049 xmlElementTablePtr table;
3050
3051 if (dtd == NULL) return(NULL);
3052 if (dtd->elements == NULL) return(NULL);
3053 table = (xmlElementTablePtr) dtd->elements;
3054
3055 return(xmlHashLookup2(table, name, prefix));
3056}
3057
3058/**
3059 * xmlGetDtdAttrDesc:
3060 * @dtd: a pointer to the DtD to search
3061 * @elem: the element name
3062 * @name: the attribute name
3063 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003064 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003065 * this element.
3066 *
3067 * returns the xmlAttributePtr if found or NULL
3068 */
3069
3070xmlAttributePtr
3071xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3072 xmlAttributeTablePtr table;
3073 xmlAttributePtr cur;
3074 xmlChar *uqname = NULL, *prefix = NULL;
3075
3076 if (dtd == NULL) return(NULL);
3077 if (dtd->attributes == NULL) return(NULL);
3078
3079 table = (xmlAttributeTablePtr) dtd->attributes;
3080 if (table == NULL)
3081 return(NULL);
3082
3083 uqname = xmlSplitQName2(name, &prefix);
3084
3085 if (uqname != NULL) {
3086 cur = xmlHashLookup3(table, uqname, prefix, elem);
3087 if (prefix != NULL) xmlFree(prefix);
3088 if (uqname != NULL) xmlFree(uqname);
3089 } else
3090 cur = xmlHashLookup3(table, name, NULL, elem);
3091 return(cur);
3092}
3093
3094/**
3095 * xmlGetDtdQAttrDesc:
3096 * @dtd: a pointer to the DtD to search
3097 * @elem: the element name
3098 * @name: the attribute name
3099 * @prefix: the attribute namespace prefix
3100 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003101 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003102 * this element.
3103 *
3104 * returns the xmlAttributePtr if found or NULL
3105 */
3106
Daniel Veillard48da9102001-08-07 01:10:10 +00003107xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003108xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3109 const xmlChar *prefix) {
3110 xmlAttributeTablePtr table;
3111
3112 if (dtd == NULL) return(NULL);
3113 if (dtd->attributes == NULL) return(NULL);
3114 table = (xmlAttributeTablePtr) dtd->attributes;
3115
3116 return(xmlHashLookup3(table, name, prefix, elem));
3117}
3118
3119/**
3120 * xmlGetDtdNotationDesc:
3121 * @dtd: a pointer to the DtD to search
3122 * @name: the notation name
3123 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003124 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003125 *
3126 * returns the xmlNotationPtr if found or NULL
3127 */
3128
3129xmlNotationPtr
3130xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3131 xmlNotationTablePtr table;
3132
3133 if (dtd == NULL) return(NULL);
3134 if (dtd->notations == NULL) return(NULL);
3135 table = (xmlNotationTablePtr) dtd->notations;
3136
3137 return(xmlHashLookup(table, name));
3138}
3139
Daniel Veillard4432df22003-09-28 18:58:27 +00003140#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003141/**
3142 * xmlValidateNotationUse:
3143 * @ctxt: the validation context
3144 * @doc: the document
3145 * @notationName: the notation name to check
3146 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003147 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003148 * - [ VC: Notation Declared ]
3149 *
3150 * returns 1 if valid or 0 otherwise
3151 */
3152
3153int
3154xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3155 const xmlChar *notationName) {
3156 xmlNotationPtr notaDecl;
3157 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3158
3159 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3160 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3161 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3162
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003163 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003164 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3165 "NOTATION %s is not declared\n",
3166 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003167 return(0);
3168 }
3169 return(1);
3170}
Daniel Veillard4432df22003-09-28 18:58:27 +00003171#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003172
3173/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003174 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003175 * @doc: the document
3176 * @name: the element name
3177 *
3178 * Search in the DtDs whether an element accept Mixed content (or ANY)
3179 * basically if it is supposed to accept text childs
3180 *
3181 * returns 0 if no, 1 if yes, and -1 if no element description is available
3182 */
3183
3184int
3185xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3186 xmlElementPtr elemDecl;
3187
3188 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3189
3190 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3191 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3192 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3193 if (elemDecl == NULL) return(-1);
3194 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003195 case XML_ELEMENT_TYPE_UNDEFINED:
3196 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003197 case XML_ELEMENT_TYPE_ELEMENT:
3198 return(0);
3199 case XML_ELEMENT_TYPE_EMPTY:
3200 /*
3201 * return 1 for EMPTY since we want VC error to pop up
3202 * on <empty> </empty> for example
3203 */
3204 case XML_ELEMENT_TYPE_ANY:
3205 case XML_ELEMENT_TYPE_MIXED:
3206 return(1);
3207 }
3208 return(1);
3209}
3210
Daniel Veillard4432df22003-09-28 18:58:27 +00003211#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003212/**
3213 * xmlValidateNameValue:
3214 * @value: an Name value
3215 *
3216 * Validate that the given value match Name production
3217 *
3218 * returns 1 if valid or 0 otherwise
3219 */
3220
Daniel Veillard9b731d72002-04-14 12:56:08 +00003221int
Owen Taylor3473f882001-02-23 17:55:21 +00003222xmlValidateNameValue(const xmlChar *value) {
3223 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003224 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003225
3226 if (value == NULL) return(0);
3227 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003228 val = xmlStringCurrentChar(NULL, cur, &len);
3229 cur += len;
3230 if (!IS_LETTER(val) && (val != '_') &&
3231 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003232 return(0);
3233 }
3234
Daniel Veillardd8224e02002-01-13 15:43:22 +00003235 val = xmlStringCurrentChar(NULL, cur, &len);
3236 cur += len;
3237 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3238 (val == '.') || (val == '-') ||
3239 (val == '_') || (val == ':') ||
3240 (IS_COMBINING(val)) ||
3241 (IS_EXTENDER(val))) {
3242 val = xmlStringCurrentChar(NULL, cur, &len);
3243 cur += len;
3244 }
Owen Taylor3473f882001-02-23 17:55:21 +00003245
Daniel Veillardd8224e02002-01-13 15:43:22 +00003246 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003247
3248 return(1);
3249}
3250
3251/**
3252 * xmlValidateNamesValue:
3253 * @value: an Names value
3254 *
3255 * Validate that the given value match Names production
3256 *
3257 * returns 1 if valid or 0 otherwise
3258 */
3259
Daniel Veillard9b731d72002-04-14 12:56:08 +00003260int
Owen Taylor3473f882001-02-23 17:55:21 +00003261xmlValidateNamesValue(const xmlChar *value) {
3262 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003263 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003264
3265 if (value == NULL) return(0);
3266 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003267 val = xmlStringCurrentChar(NULL, cur, &len);
3268 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003269
Daniel Veillardd8224e02002-01-13 15:43:22 +00003270 if (!IS_LETTER(val) && (val != '_') &&
3271 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003272 return(0);
3273 }
3274
Daniel Veillardd8224e02002-01-13 15:43:22 +00003275 val = xmlStringCurrentChar(NULL, cur, &len);
3276 cur += len;
3277 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3278 (val == '.') || (val == '-') ||
3279 (val == '_') || (val == ':') ||
3280 (IS_COMBINING(val)) ||
3281 (IS_EXTENDER(val))) {
3282 val = xmlStringCurrentChar(NULL, cur, &len);
3283 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003284 }
3285
Daniel Veillardd8224e02002-01-13 15:43:22 +00003286 while (IS_BLANK(val)) {
3287 while (IS_BLANK(val)) {
3288 val = xmlStringCurrentChar(NULL, cur, &len);
3289 cur += len;
3290 }
3291
3292 if (!IS_LETTER(val) && (val != '_') &&
3293 (val != ':')) {
3294 return(0);
3295 }
3296 val = xmlStringCurrentChar(NULL, cur, &len);
3297 cur += len;
3298
3299 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3300 (val == '.') || (val == '-') ||
3301 (val == '_') || (val == ':') ||
3302 (IS_COMBINING(val)) ||
3303 (IS_EXTENDER(val))) {
3304 val = xmlStringCurrentChar(NULL, cur, &len);
3305 cur += len;
3306 }
3307 }
3308
3309 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003310
3311 return(1);
3312}
3313
3314/**
3315 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003316 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003317 *
3318 * Validate that the given value match Nmtoken production
3319 *
3320 * [ VC: Name Token ]
3321 *
3322 * returns 1 if valid or 0 otherwise
3323 */
3324
Daniel Veillard9b731d72002-04-14 12:56:08 +00003325int
Owen Taylor3473f882001-02-23 17:55:21 +00003326xmlValidateNmtokenValue(const xmlChar *value) {
3327 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003328 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003329
3330 if (value == NULL) return(0);
3331 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003332 val = xmlStringCurrentChar(NULL, cur, &len);
3333 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003334
Daniel Veillardd8224e02002-01-13 15:43:22 +00003335 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3336 (val != '.') && (val != '-') &&
3337 (val != '_') && (val != ':') &&
3338 (!IS_COMBINING(val)) &&
3339 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003340 return(0);
3341
Daniel Veillardd8224e02002-01-13 15:43:22 +00003342 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3343 (val == '.') || (val == '-') ||
3344 (val == '_') || (val == ':') ||
3345 (IS_COMBINING(val)) ||
3346 (IS_EXTENDER(val))) {
3347 val = xmlStringCurrentChar(NULL, cur, &len);
3348 cur += len;
3349 }
Owen Taylor3473f882001-02-23 17:55:21 +00003350
Daniel Veillardd8224e02002-01-13 15:43:22 +00003351 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003352
3353 return(1);
3354}
3355
3356/**
3357 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003358 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003359 *
3360 * Validate that the given value match Nmtokens production
3361 *
3362 * [ VC: Name Token ]
3363 *
3364 * returns 1 if valid or 0 otherwise
3365 */
3366
Daniel Veillard9b731d72002-04-14 12:56:08 +00003367int
Owen Taylor3473f882001-02-23 17:55:21 +00003368xmlValidateNmtokensValue(const xmlChar *value) {
3369 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003370 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003371
3372 if (value == NULL) return(0);
3373 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003374 val = xmlStringCurrentChar(NULL, cur, &len);
3375 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003376
Daniel Veillardd8224e02002-01-13 15:43:22 +00003377 while (IS_BLANK(val)) {
3378 val = xmlStringCurrentChar(NULL, cur, &len);
3379 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003380 }
3381
Daniel Veillardd8224e02002-01-13 15:43:22 +00003382 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3383 (val != '.') && (val != '-') &&
3384 (val != '_') && (val != ':') &&
3385 (!IS_COMBINING(val)) &&
3386 (!IS_EXTENDER(val)))
3387 return(0);
3388
3389 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3390 (val == '.') || (val == '-') ||
3391 (val == '_') || (val == ':') ||
3392 (IS_COMBINING(val)) ||
3393 (IS_EXTENDER(val))) {
3394 val = xmlStringCurrentChar(NULL, cur, &len);
3395 cur += len;
3396 }
3397
3398 while (IS_BLANK(val)) {
3399 while (IS_BLANK(val)) {
3400 val = xmlStringCurrentChar(NULL, cur, &len);
3401 cur += len;
3402 }
3403 if (val == 0) return(1);
3404
3405 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3406 (val != '.') && (val != '-') &&
3407 (val != '_') && (val != ':') &&
3408 (!IS_COMBINING(val)) &&
3409 (!IS_EXTENDER(val)))
3410 return(0);
3411
3412 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3413 (val == '.') || (val == '-') ||
3414 (val == '_') || (val == ':') ||
3415 (IS_COMBINING(val)) ||
3416 (IS_EXTENDER(val))) {
3417 val = xmlStringCurrentChar(NULL, cur, &len);
3418 cur += len;
3419 }
3420 }
3421
3422 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003423
3424 return(1);
3425}
3426
3427/**
3428 * xmlValidateNotationDecl:
3429 * @ctxt: the validation context
3430 * @doc: a document instance
3431 * @nota: a notation definition
3432 *
3433 * Try to validate a single notation definition
3434 * basically it does the following checks as described by the
3435 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003436 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003437 * But this function get called anyway ...
3438 *
3439 * returns 1 if valid or 0 otherwise
3440 */
3441
3442int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003443xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3444 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003445 int ret = 1;
3446
3447 return(ret);
3448}
3449
3450/**
3451 * xmlValidateAttributeValue:
3452 * @type: an attribute type
3453 * @value: an attribute value
3454 *
3455 * Validate that the given attribute value match the proper production
3456 *
3457 * [ VC: ID ]
3458 * Values of type ID must match the Name production....
3459 *
3460 * [ VC: IDREF ]
3461 * Values of type IDREF must match the Name production, and values
3462 * of type IDREFS must match Names ...
3463 *
3464 * [ VC: Entity Name ]
3465 * Values of type ENTITY must match the Name production, values
3466 * of type ENTITIES must match Names ...
3467 *
3468 * [ VC: Name Token ]
3469 * Values of type NMTOKEN must match the Nmtoken production; values
3470 * of type NMTOKENS must match Nmtokens.
3471 *
3472 * returns 1 if valid or 0 otherwise
3473 */
3474
3475int
3476xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3477 switch (type) {
3478 case XML_ATTRIBUTE_ENTITIES:
3479 case XML_ATTRIBUTE_IDREFS:
3480 return(xmlValidateNamesValue(value));
3481 case XML_ATTRIBUTE_ENTITY:
3482 case XML_ATTRIBUTE_IDREF:
3483 case XML_ATTRIBUTE_ID:
3484 case XML_ATTRIBUTE_NOTATION:
3485 return(xmlValidateNameValue(value));
3486 case XML_ATTRIBUTE_NMTOKENS:
3487 case XML_ATTRIBUTE_ENUMERATION:
3488 return(xmlValidateNmtokensValue(value));
3489 case XML_ATTRIBUTE_NMTOKEN:
3490 return(xmlValidateNmtokenValue(value));
3491 case XML_ATTRIBUTE_CDATA:
3492 break;
3493 }
3494 return(1);
3495}
3496
3497/**
3498 * xmlValidateAttributeValue2:
3499 * @ctxt: the validation context
3500 * @doc: the document
3501 * @name: the attribute name (used for error reporting only)
3502 * @type: the attribute type
3503 * @value: the attribute value
3504 *
3505 * Validate that the given attribute value match a given type.
3506 * This typically cannot be done before having finished parsing
3507 * the subsets.
3508 *
3509 * [ VC: IDREF ]
3510 * Values of type IDREF must match one of the declared IDs
3511 * Values of type IDREFS must match a sequence of the declared IDs
3512 * each Name must match the value of an ID attribute on some element
3513 * in the XML document; i.e. IDREF values must match the value of
3514 * some ID attribute
3515 *
3516 * [ VC: Entity Name ]
3517 * Values of type ENTITY must match one declared entity
3518 * Values of type ENTITIES must match a sequence of declared entities
3519 *
3520 * [ VC: Notation Attributes ]
3521 * all notation names in the declaration must be declared.
3522 *
3523 * returns 1 if valid or 0 otherwise
3524 */
3525
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003526static int
Owen Taylor3473f882001-02-23 17:55:21 +00003527xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3528 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3529 int ret = 1;
3530 switch (type) {
3531 case XML_ATTRIBUTE_IDREFS:
3532 case XML_ATTRIBUTE_IDREF:
3533 case XML_ATTRIBUTE_ID:
3534 case XML_ATTRIBUTE_NMTOKENS:
3535 case XML_ATTRIBUTE_ENUMERATION:
3536 case XML_ATTRIBUTE_NMTOKEN:
3537 case XML_ATTRIBUTE_CDATA:
3538 break;
3539 case XML_ATTRIBUTE_ENTITY: {
3540 xmlEntityPtr ent;
3541
3542 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003543 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003544 if ((ent == NULL) && (doc->standalone == 1)) {
3545 doc->standalone = 0;
3546 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003547 }
Owen Taylor3473f882001-02-23 17:55:21 +00003548 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003549 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3550 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003551 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003552 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003553 ret = 0;
3554 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003555 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3556 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003557 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003558 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003559 ret = 0;
3560 }
3561 break;
3562 }
3563 case XML_ATTRIBUTE_ENTITIES: {
3564 xmlChar *dup, *nam = NULL, *cur, save;
3565 xmlEntityPtr ent;
3566
3567 dup = xmlStrdup(value);
3568 if (dup == NULL)
3569 return(0);
3570 cur = dup;
3571 while (*cur != 0) {
3572 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003573 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003574 save = *cur;
3575 *cur = 0;
3576 ent = xmlGetDocEntity(doc, nam);
3577 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003578 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3579 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003580 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003581 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003582 ret = 0;
3583 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003584 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3585 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003586 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003587 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003588 ret = 0;
3589 }
3590 if (save == 0)
3591 break;
3592 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003593 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003594 }
3595 xmlFree(dup);
3596 break;
3597 }
3598 case XML_ATTRIBUTE_NOTATION: {
3599 xmlNotationPtr nota;
3600
3601 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3602 if ((nota == NULL) && (doc->extSubset != NULL))
3603 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3604
3605 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003606 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3607 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003608 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003609 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003610 ret = 0;
3611 }
3612 break;
3613 }
3614 }
3615 return(ret);
3616}
3617
3618/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003619 * xmlValidCtxtNormalizeAttributeValue:
3620 * @ctxt: the validation context
3621 * @doc: the document
3622 * @elem: the parent
3623 * @name: the attribute name
3624 * @value: the attribute value
3625 * @ctxt: the validation context or NULL
3626 *
3627 * Does the validation related extra step of the normalization of attribute
3628 * values:
3629 *
3630 * If the declared value is not CDATA, then the XML processor must further
3631 * process the normalized attribute value by discarding any leading and
3632 * trailing space (#x20) characters, and by replacing sequences of space
3633 * (#x20) characters by single space (#x20) character.
3634 *
3635 * Also check VC: Standalone Document Declaration in P32, and update
3636 * ctxt->valid accordingly
3637 *
3638 * returns a new normalized string if normalization is needed, NULL otherwise
3639 * the caller must free the returned value.
3640 */
3641
3642xmlChar *
3643xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3644 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3645 xmlChar *ret, *dst;
3646 const xmlChar *src;
3647 xmlAttributePtr attrDecl = NULL;
3648 int extsubset = 0;
3649
3650 if (doc == NULL) return(NULL);
3651 if (elem == NULL) return(NULL);
3652 if (name == NULL) return(NULL);
3653 if (value == NULL) return(NULL);
3654
3655 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003656 xmlChar fn[50];
3657 xmlChar *fullname;
3658
3659 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3660 if (fullname == NULL)
3661 return(0);
3662 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003663 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003664 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003665 if (attrDecl != NULL)
3666 extsubset = 1;
3667 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003668 if ((fullname != fn) && (fullname != elem->name))
3669 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003670 }
3671 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3672 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3673 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3674 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3675 if (attrDecl != NULL)
3676 extsubset = 1;
3677 }
3678
3679 if (attrDecl == NULL)
3680 return(NULL);
3681 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3682 return(NULL);
3683
3684 ret = xmlStrdup(value);
3685 if (ret == NULL)
3686 return(NULL);
3687 src = value;
3688 dst = ret;
3689 while (*src == 0x20) src++;
3690 while (*src != 0) {
3691 if (*src == 0x20) {
3692 while (*src == 0x20) src++;
3693 if (*src != 0)
3694 *dst++ = 0x20;
3695 } else {
3696 *dst++ = *src++;
3697 }
3698 }
3699 *dst = 0;
3700 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003701 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003702"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003703 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003704 ctxt->valid = 0;
3705 }
3706 return(ret);
3707}
3708
3709/**
Owen Taylor3473f882001-02-23 17:55:21 +00003710 * xmlValidNormalizeAttributeValue:
3711 * @doc: the document
3712 * @elem: the parent
3713 * @name: the attribute name
3714 * @value: the attribute value
3715 *
3716 * Does the validation related extra step of the normalization of attribute
3717 * values:
3718 *
3719 * If the declared value is not CDATA, then the XML processor must further
3720 * process the normalized attribute value by discarding any leading and
3721 * trailing space (#x20) characters, and by replacing sequences of space
3722 * (#x20) characters by single space (#x20) character.
3723 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003724 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003725 * the caller must free the returned value.
3726 */
3727
3728xmlChar *
3729xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3730 const xmlChar *name, const xmlChar *value) {
3731 xmlChar *ret, *dst;
3732 const xmlChar *src;
3733 xmlAttributePtr attrDecl = NULL;
3734
3735 if (doc == NULL) return(NULL);
3736 if (elem == NULL) return(NULL);
3737 if (name == NULL) return(NULL);
3738 if (value == NULL) return(NULL);
3739
3740 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003741 xmlChar fn[50];
3742 xmlChar *fullname;
3743
3744 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3745 if (fullname == NULL)
3746 return(0);
3747 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003748 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003749 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3750 if ((fullname != fn) && (fullname != elem->name))
3751 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003752 }
3753 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3754 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3755 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3756
3757 if (attrDecl == NULL)
3758 return(NULL);
3759 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3760 return(NULL);
3761
3762 ret = xmlStrdup(value);
3763 if (ret == NULL)
3764 return(NULL);
3765 src = value;
3766 dst = ret;
3767 while (*src == 0x20) src++;
3768 while (*src != 0) {
3769 if (*src == 0x20) {
3770 while (*src == 0x20) src++;
3771 if (*src != 0)
3772 *dst++ = 0x20;
3773 } else {
3774 *dst++ = *src++;
3775 }
3776 }
3777 *dst = 0;
3778 return(ret);
3779}
3780
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003781static void
Owen Taylor3473f882001-02-23 17:55:21 +00003782xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003783 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003784 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3785}
3786
3787/**
3788 * xmlValidateAttributeDecl:
3789 * @ctxt: the validation context
3790 * @doc: a document instance
3791 * @attr: an attribute definition
3792 *
3793 * Try to validate a single attribute definition
3794 * basically it does the following checks as described by the
3795 * XML-1.0 recommendation:
3796 * - [ VC: Attribute Default Legal ]
3797 * - [ VC: Enumeration ]
3798 * - [ VC: ID Attribute Default ]
3799 *
3800 * The ID/IDREF uniqueness and matching are done separately
3801 *
3802 * returns 1 if valid or 0 otherwise
3803 */
3804
3805int
3806xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3807 xmlAttributePtr attr) {
3808 int ret = 1;
3809 int val;
3810 CHECK_DTD;
3811 if(attr == NULL) return(1);
3812
3813 /* Attribute Default Legal */
3814 /* Enumeration */
3815 if (attr->defaultValue != NULL) {
3816 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3817 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003818 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003819 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003820 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003821 }
3822 ret &= val;
3823 }
3824
3825 /* ID Attribute Default */
3826 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3827 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3828 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003829 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003830 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003831 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003832 ret = 0;
3833 }
3834
3835 /* One ID per Element Type */
3836 if (attr->atype == XML_ATTRIBUTE_ID) {
3837 int nbId;
3838
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003839 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00003840 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3841 attr->elem);
3842 if (elem != NULL) {
3843 nbId = xmlScanIDAttributeDecl(NULL, elem);
3844 } else {
3845 xmlAttributeTablePtr table;
3846
3847 /*
3848 * The attribute may be declared in the internal subset and the
3849 * element in the external subset.
3850 */
3851 nbId = 0;
3852 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3853 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3854 xmlValidateAttributeIdCallback, &nbId);
3855 }
3856 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003857
3858 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003859 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3860 attr->elem, nbId, attr->name);
3861 } else if (doc->extSubset != NULL) {
3862 int extId = 0;
3863 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3864 if (elem != NULL) {
3865 extId = xmlScanIDAttributeDecl(NULL, elem);
3866 }
3867 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003868 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003869 "Element %s has %d ID attribute defined in the external subset : %s\n",
3870 attr->elem, extId, attr->name);
3871 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003872 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003873"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003874 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003875 }
3876 }
3877 }
3878
3879 /* Validity Constraint: Enumeration */
3880 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3881 xmlEnumerationPtr tree = attr->tree;
3882 while (tree != NULL) {
3883 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3884 tree = tree->next;
3885 }
3886 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003887 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003888"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003889 attr->defaultValue, attr->name, attr->elem);
3890 ret = 0;
3891 }
3892 }
3893
3894 return(ret);
3895}
3896
3897/**
3898 * xmlValidateElementDecl:
3899 * @ctxt: the validation context
3900 * @doc: a document instance
3901 * @elem: an element definition
3902 *
3903 * Try to validate a single element definition
3904 * basically it does the following checks as described by the
3905 * XML-1.0 recommendation:
3906 * - [ VC: One ID per Element Type ]
3907 * - [ VC: No Duplicate Types ]
3908 * - [ VC: Unique Element Type Declaration ]
3909 *
3910 * returns 1 if valid or 0 otherwise
3911 */
3912
3913int
3914xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3915 xmlElementPtr elem) {
3916 int ret = 1;
3917 xmlElementPtr tst;
3918
3919 CHECK_DTD;
3920
3921 if (elem == NULL) return(1);
3922
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003923#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00003924#ifdef LIBXML_REGEXP_ENABLED
3925 /* Build the regexp associated to the content model */
3926 ret = xmlValidBuildContentModel(ctxt, elem);
3927#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003928#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00003929
Owen Taylor3473f882001-02-23 17:55:21 +00003930 /* No Duplicate Types */
3931 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3932 xmlElementContentPtr cur, next;
3933 const xmlChar *name;
3934
3935 cur = elem->content;
3936 while (cur != NULL) {
3937 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3938 if (cur->c1 == NULL) break;
3939 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3940 name = cur->c1->name;
3941 next = cur->c2;
3942 while (next != NULL) {
3943 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00003944 if ((xmlStrEqual(next->name, name)) &&
3945 (xmlStrEqual(next->prefix, cur->prefix))) {
3946 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003947 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00003948 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003949 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003950 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003951 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003952 "Definition of %s has duplicate references of %s:%s\n",
3953 elem->name, cur->prefix, name);
3954 }
Owen Taylor3473f882001-02-23 17:55:21 +00003955 ret = 0;
3956 }
3957 break;
3958 }
3959 if (next->c1 == NULL) break;
3960 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00003961 if ((xmlStrEqual(next->c1->name, name)) &&
3962 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
3963 if (cur->prefix == NULL) {
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 to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003966 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003967 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003968 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003969 "Definition of %s has duplicate references to %s:%s\n",
3970 elem->name, cur->prefix, name);
3971 }
Owen Taylor3473f882001-02-23 17:55:21 +00003972 ret = 0;
3973 }
3974 next = next->c2;
3975 }
3976 }
3977 cur = cur->c2;
3978 }
3979 }
3980
3981 /* VC: Unique Element Type Declaration */
3982 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003983 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00003984 ((tst->prefix == elem->prefix) ||
3985 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00003986 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003987 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
3988 "Redefinition of element %s\n",
3989 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003990 ret = 0;
3991 }
3992 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003993 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00003994 ((tst->prefix == elem->prefix) ||
3995 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00003996 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003997 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
3998 "Redefinition of element %s\n",
3999 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004000 ret = 0;
4001 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004002 /* One ID per Element Type
4003 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004004 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4005 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004006 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004007 return(ret);
4008}
4009
4010/**
4011 * xmlValidateOneAttribute:
4012 * @ctxt: the validation context
4013 * @doc: a document instance
4014 * @elem: an element instance
4015 * @attr: an attribute instance
4016 * @value: the attribute value (without entities processing)
4017 *
4018 * Try to validate a single attribute for an element
4019 * basically it does the following checks as described by the
4020 * XML-1.0 recommendation:
4021 * - [ VC: Attribute Value Type ]
4022 * - [ VC: Fixed Attribute Default ]
4023 * - [ VC: Entity Name ]
4024 * - [ VC: Name Token ]
4025 * - [ VC: ID ]
4026 * - [ VC: IDREF ]
4027 * - [ VC: Entity Name ]
4028 * - [ VC: Notation Attributes ]
4029 *
4030 * The ID/IDREF uniqueness and matching are done separately
4031 *
4032 * returns 1 if valid or 0 otherwise
4033 */
4034
4035int
4036xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004037 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4038{
Owen Taylor3473f882001-02-23 17:55:21 +00004039 xmlAttributePtr attrDecl = NULL;
4040 int val;
4041 int ret = 1;
4042
4043 CHECK_DTD;
4044 if ((elem == NULL) || (elem->name == NULL)) return(0);
4045 if ((attr == NULL) || (attr->name == NULL)) return(0);
4046
4047 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004048 xmlChar fn[50];
4049 xmlChar *fullname;
4050
4051 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4052 if (fullname == NULL)
4053 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004054 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004055 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004056 attr->name, attr->ns->prefix);
4057 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004058 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004059 attr->name, attr->ns->prefix);
4060 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004061 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004062 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4063 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004064 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004065 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004066 if ((fullname != fn) && (fullname != elem->name))
4067 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004068 }
4069 if (attrDecl == NULL) {
4070 if (attr->ns != NULL) {
4071 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4072 attr->name, attr->ns->prefix);
4073 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4074 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4075 attr->name, attr->ns->prefix);
4076 } else {
4077 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4078 elem->name, attr->name);
4079 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4080 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4081 elem->name, attr->name);
4082 }
4083 }
4084
4085
4086 /* Validity Constraint: Attribute Value Type */
4087 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004088 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004089 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004090 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004091 return(0);
4092 }
4093 attr->atype = attrDecl->atype;
4094
4095 val = xmlValidateAttributeValue(attrDecl->atype, value);
4096 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004097 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004098 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004099 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004100 ret = 0;
4101 }
4102
4103 /* Validity constraint: Fixed Attribute Default */
4104 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4105 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004106 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004107 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004108 attr->name, elem->name, attrDecl->defaultValue);
4109 ret = 0;
4110 }
4111 }
4112
4113 /* Validity Constraint: ID uniqueness */
4114 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4115 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4116 ret = 0;
4117 }
4118
4119 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4120 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4121 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4122 ret = 0;
4123 }
4124
4125 /* Validity Constraint: Notation Attributes */
4126 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4127 xmlEnumerationPtr tree = attrDecl->tree;
4128 xmlNotationPtr nota;
4129
4130 /* First check that the given NOTATION was declared */
4131 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4132 if (nota == NULL)
4133 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4134
4135 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004136 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004137 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004138 value, attr->name, elem->name);
4139 ret = 0;
4140 }
4141
4142 /* Second, verify that it's among the list */
4143 while (tree != NULL) {
4144 if (xmlStrEqual(tree->name, value)) break;
4145 tree = tree->next;
4146 }
4147 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004148 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004149"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004150 value, attr->name, elem->name);
4151 ret = 0;
4152 }
4153 }
4154
4155 /* Validity Constraint: Enumeration */
4156 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4157 xmlEnumerationPtr tree = attrDecl->tree;
4158 while (tree != NULL) {
4159 if (xmlStrEqual(tree->name, value)) break;
4160 tree = tree->next;
4161 }
4162 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004163 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004164 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004165 value, attr->name, elem->name);
4166 ret = 0;
4167 }
4168 }
4169
4170 /* Fixed Attribute Default */
4171 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4172 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004173 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004174 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004175 attr->name, elem->name, attrDecl->defaultValue);
4176 ret = 0;
4177 }
4178
4179 /* Extra check for the attribute value */
4180 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4181 attrDecl->atype, value);
4182
4183 return(ret);
4184}
4185
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004186/**
4187 * xmlValidateOneNamespace:
4188 * @ctxt: the validation context
4189 * @doc: a document instance
4190 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004191 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004192 * @ns: an namespace declaration instance
4193 * @value: the attribute value (without entities processing)
4194 *
4195 * Try to validate a single namespace declaration for an element
4196 * basically it does the following checks as described by the
4197 * XML-1.0 recommendation:
4198 * - [ VC: Attribute Value Type ]
4199 * - [ VC: Fixed Attribute Default ]
4200 * - [ VC: Entity Name ]
4201 * - [ VC: Name Token ]
4202 * - [ VC: ID ]
4203 * - [ VC: IDREF ]
4204 * - [ VC: Entity Name ]
4205 * - [ VC: Notation Attributes ]
4206 *
4207 * The ID/IDREF uniqueness and matching are done separately
4208 *
4209 * returns 1 if valid or 0 otherwise
4210 */
4211
4212int
4213xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4214xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4215 /* xmlElementPtr elemDecl; */
4216 xmlAttributePtr attrDecl = NULL;
4217 int val;
4218 int ret = 1;
4219
4220 CHECK_DTD;
4221 if ((elem == NULL) || (elem->name == NULL)) return(0);
4222 if ((ns == NULL) || (ns->href == NULL)) return(0);
4223
4224 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004225 xmlChar fn[50];
4226 xmlChar *fullname;
4227
4228 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4229 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004230 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004231 return(0);
4232 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004233 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004234 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004235 ns->prefix, BAD_CAST "xmlns");
4236 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004237 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004238 ns->prefix, BAD_CAST "xmlns");
4239 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004240 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004241 BAD_CAST "xmlns");
4242 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004243 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004244 BAD_CAST "xmlns");
4245 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004246 if ((fullname != fn) && (fullname != elem->name))
4247 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004248 }
4249 if (attrDecl == NULL) {
4250 if (ns->prefix != NULL) {
4251 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4252 ns->prefix, BAD_CAST "xmlns");
4253 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4254 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4255 ns->prefix, BAD_CAST "xmlns");
4256 } else {
4257 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4258 elem->name, BAD_CAST "xmlns");
4259 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4260 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4261 elem->name, BAD_CAST "xmlns");
4262 }
4263 }
4264
4265
4266 /* Validity Constraint: Attribute Value Type */
4267 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004268 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004269 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004270 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004271 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004272 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004273 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004274 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004275 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004276 }
4277 return(0);
4278 }
4279
4280 val = xmlValidateAttributeValue(attrDecl->atype, value);
4281 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004282 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004283 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004284 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004285 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004286 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004287 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004288 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004289 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004290 }
4291 ret = 0;
4292 }
4293
4294 /* Validity constraint: Fixed Attribute Default */
4295 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4296 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004297 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004298 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004299 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4300 ns->prefix, elem->name, attrDecl->defaultValue);
4301 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004302 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004303 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004304 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004305 }
4306 ret = 0;
4307 }
4308 }
4309
4310 /* Validity Constraint: ID uniqueness */
4311 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4312 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4313 ret = 0;
4314 }
4315
4316 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4317 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4318 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4319 ret = 0;
4320 }
4321
4322 /* Validity Constraint: Notation Attributes */
4323 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4324 xmlEnumerationPtr tree = attrDecl->tree;
4325 xmlNotationPtr nota;
4326
4327 /* First check that the given NOTATION was declared */
4328 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4329 if (nota == NULL)
4330 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4331
4332 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004333 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004334 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004335 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4336 value, ns->prefix, elem->name);
4337 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004338 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004339 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004340 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004341 }
4342 ret = 0;
4343 }
4344
4345 /* Second, verify that it's among the list */
4346 while (tree != NULL) {
4347 if (xmlStrEqual(tree->name, value)) break;
4348 tree = tree->next;
4349 }
4350 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004351 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004352 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004353"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4354 value, ns->prefix, elem->name);
4355 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004356 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004357"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004358 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004359 }
4360 ret = 0;
4361 }
4362 }
4363
4364 /* Validity Constraint: Enumeration */
4365 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4366 xmlEnumerationPtr tree = attrDecl->tree;
4367 while (tree != NULL) {
4368 if (xmlStrEqual(tree->name, value)) break;
4369 tree = tree->next;
4370 }
4371 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004372 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004373 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004374"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4375 value, ns->prefix, elem->name);
4376 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004377 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004378"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004379 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004380 }
4381 ret = 0;
4382 }
4383 }
4384
4385 /* Fixed Attribute Default */
4386 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4387 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004388 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004389 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004390 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4391 ns->prefix, elem->name, attrDecl->defaultValue);
4392 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004393 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004394 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004395 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004396 }
4397 ret = 0;
4398 }
4399
4400 /* Extra check for the attribute value */
4401 if (ns->prefix != NULL) {
4402 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4403 attrDecl->atype, value);
4404 } else {
4405 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4406 attrDecl->atype, value);
4407 }
4408
4409 return(ret);
4410}
4411
Daniel Veillard118aed72002-09-24 14:13:13 +00004412#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004413/**
4414 * xmlValidateSkipIgnorable:
4415 * @ctxt: the validation context
4416 * @child: the child list
4417 *
4418 * Skip ignorable elements w.r.t. the validation process
4419 *
4420 * returns the first element to consider for validation of the content model
4421 */
4422
4423static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004424xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004425 while (child != NULL) {
4426 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004427 /* These things are ignored (skipped) during validation. */
4428 case XML_PI_NODE:
4429 case XML_COMMENT_NODE:
4430 case XML_XINCLUDE_START:
4431 case XML_XINCLUDE_END:
4432 child = child->next;
4433 break;
4434 case XML_TEXT_NODE:
4435 if (xmlIsBlankNode(child))
4436 child = child->next;
4437 else
4438 return(child);
4439 break;
4440 /* keep current node */
4441 default:
4442 return(child);
4443 }
4444 }
4445 return(child);
4446}
4447
4448/**
4449 * xmlValidateElementType:
4450 * @ctxt: the validation context
4451 *
4452 * Try to validate the content model of an element internal function
4453 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004454 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4455 * reference is found and -3 if the validation succeeded but
4456 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004457 */
4458
4459static int
4460xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004461 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004462 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004463
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004464 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004465 if ((NODE == NULL) && (CONT == NULL))
4466 return(1);
4467 if ((NODE == NULL) &&
4468 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4469 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4470 return(1);
4471 }
4472 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004473 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004474 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004475
4476 /*
4477 * We arrive here when more states need to be examined
4478 */
4479cont:
4480
4481 /*
4482 * We just recovered from a rollback generated by a possible
4483 * epsilon transition, go directly to the analysis phase
4484 */
4485 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004486 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004487 DEBUG_VALID_STATE(NODE, CONT)
4488 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004489 goto analyze;
4490 }
4491
4492 DEBUG_VALID_STATE(NODE, CONT)
4493 /*
4494 * we may have to save a backup state here. This is the equivalent
4495 * of handling epsilon transition in NFAs.
4496 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004497 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004498 ((CONT->parent == NULL) ||
4499 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004500 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004501 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004502 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004503 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004504 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4505 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004506 }
4507
4508
4509 /*
4510 * Check first if the content matches
4511 */
4512 switch (CONT->type) {
4513 case XML_ELEMENT_CONTENT_PCDATA:
4514 if (NODE == NULL) {
4515 DEBUG_VALID_MSG("pcdata failed no node");
4516 ret = 0;
4517 break;
4518 }
4519 if (NODE->type == XML_TEXT_NODE) {
4520 DEBUG_VALID_MSG("pcdata found, skip to next");
4521 /*
4522 * go to next element in the content model
4523 * skipping ignorable elems
4524 */
4525 do {
4526 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004527 NODE = xmlValidateSkipIgnorable(NODE);
4528 if ((NODE != NULL) &&
4529 (NODE->type == XML_ENTITY_REF_NODE))
4530 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004531 } while ((NODE != NULL) &&
4532 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004533 (NODE->type != XML_TEXT_NODE) &&
4534 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004535 ret = 1;
4536 break;
4537 } else {
4538 DEBUG_VALID_MSG("pcdata failed");
4539 ret = 0;
4540 break;
4541 }
4542 break;
4543 case XML_ELEMENT_CONTENT_ELEMENT:
4544 if (NODE == NULL) {
4545 DEBUG_VALID_MSG("element failed no node");
4546 ret = 0;
4547 break;
4548 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004549 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4550 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004551 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004552 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4553 ret = (CONT->prefix == NULL);
4554 } else if (CONT->prefix == NULL) {
4555 ret = 0;
4556 } else {
4557 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4558 }
4559 }
4560 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004561 DEBUG_VALID_MSG("element found, skip to next");
4562 /*
4563 * go to next element in the content model
4564 * skipping ignorable elems
4565 */
4566 do {
4567 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004568 NODE = xmlValidateSkipIgnorable(NODE);
4569 if ((NODE != NULL) &&
4570 (NODE->type == XML_ENTITY_REF_NODE))
4571 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004572 } while ((NODE != NULL) &&
4573 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004574 (NODE->type != XML_TEXT_NODE) &&
4575 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004576 } else {
4577 DEBUG_VALID_MSG("element failed");
4578 ret = 0;
4579 break;
4580 }
4581 break;
4582 case XML_ELEMENT_CONTENT_OR:
4583 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004584 * Small optimization.
4585 */
4586 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4587 if ((NODE == NULL) ||
4588 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4589 DEPTH++;
4590 CONT = CONT->c2;
4591 goto cont;
4592 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004593 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4594 ret = (CONT->c1->prefix == NULL);
4595 } else if (CONT->c1->prefix == NULL) {
4596 ret = 0;
4597 } else {
4598 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4599 }
4600 if (ret == 0) {
4601 DEPTH++;
4602 CONT = CONT->c2;
4603 goto cont;
4604 }
Daniel Veillard85349052001-04-20 13:48:21 +00004605 }
4606
4607 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004608 * save the second branch 'or' branch
4609 */
4610 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004611 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4612 OCCURS, ROLLBACK_OR) < 0)
4613 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004614 DEPTH++;
4615 CONT = CONT->c1;
4616 goto cont;
4617 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004618 /*
4619 * Small optimization.
4620 */
4621 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4622 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4623 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4624 if ((NODE == NULL) ||
4625 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4626 DEPTH++;
4627 CONT = CONT->c2;
4628 goto cont;
4629 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004630 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4631 ret = (CONT->c1->prefix == NULL);
4632 } else if (CONT->c1->prefix == NULL) {
4633 ret = 0;
4634 } else {
4635 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4636 }
4637 if (ret == 0) {
4638 DEPTH++;
4639 CONT = CONT->c2;
4640 goto cont;
4641 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004642 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004643 DEPTH++;
4644 CONT = CONT->c1;
4645 goto cont;
4646 }
4647
4648 /*
4649 * At this point handle going up in the tree
4650 */
4651 if (ret == -1) {
4652 DEBUG_VALID_MSG("error found returning");
4653 return(ret);
4654 }
4655analyze:
4656 while (CONT != NULL) {
4657 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004658 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004659 * this level.
4660 */
4661 if (ret == 0) {
4662 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004663 xmlNodePtr cur;
4664
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004665 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004666 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004667 DEBUG_VALID_MSG("Once branch failed, rollback");
4668 if (vstateVPop(ctxt) < 0 ) {
4669 DEBUG_VALID_MSG("exhaustion, failed");
4670 return(0);
4671 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004672 if (cur != ctxt->vstate->node)
4673 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004674 goto cont;
4675 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004676 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004677 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004678 DEBUG_VALID_MSG("Plus branch failed, rollback");
4679 if (vstateVPop(ctxt) < 0 ) {
4680 DEBUG_VALID_MSG("exhaustion, failed");
4681 return(0);
4682 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004683 if (cur != ctxt->vstate->node)
4684 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004685 goto cont;
4686 }
4687 DEBUG_VALID_MSG("Plus branch found");
4688 ret = 1;
4689 break;
4690 case XML_ELEMENT_CONTENT_MULT:
4691#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004692 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004693 DEBUG_VALID_MSG("Mult branch failed");
4694 } else {
4695 DEBUG_VALID_MSG("Mult branch found");
4696 }
4697#endif
4698 ret = 1;
4699 break;
4700 case XML_ELEMENT_CONTENT_OPT:
4701 DEBUG_VALID_MSG("Option branch failed");
4702 ret = 1;
4703 break;
4704 }
4705 } else {
4706 switch (CONT->ocur) {
4707 case XML_ELEMENT_CONTENT_OPT:
4708 DEBUG_VALID_MSG("Option branch succeeded");
4709 ret = 1;
4710 break;
4711 case XML_ELEMENT_CONTENT_ONCE:
4712 DEBUG_VALID_MSG("Once branch succeeded");
4713 ret = 1;
4714 break;
4715 case XML_ELEMENT_CONTENT_PLUS:
4716 if (STATE == ROLLBACK_PARENT) {
4717 DEBUG_VALID_MSG("Plus branch rollback");
4718 ret = 1;
4719 break;
4720 }
4721 if (NODE == NULL) {
4722 DEBUG_VALID_MSG("Plus branch exhausted");
4723 ret = 1;
4724 break;
4725 }
4726 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004727 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004728 goto cont;
4729 case XML_ELEMENT_CONTENT_MULT:
4730 if (STATE == ROLLBACK_PARENT) {
4731 DEBUG_VALID_MSG("Mult branch rollback");
4732 ret = 1;
4733 break;
4734 }
4735 if (NODE == NULL) {
4736 DEBUG_VALID_MSG("Mult branch exhausted");
4737 ret = 1;
4738 break;
4739 }
4740 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004741 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004742 goto cont;
4743 }
4744 }
4745 STATE = 0;
4746
4747 /*
4748 * Then act accordingly at the parent level
4749 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004750 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004751 if (CONT->parent == NULL)
4752 break;
4753
4754 switch (CONT->parent->type) {
4755 case XML_ELEMENT_CONTENT_PCDATA:
4756 DEBUG_VALID_MSG("Error: parent pcdata");
4757 return(-1);
4758 case XML_ELEMENT_CONTENT_ELEMENT:
4759 DEBUG_VALID_MSG("Error: parent element");
4760 return(-1);
4761 case XML_ELEMENT_CONTENT_OR:
4762 if (ret == 1) {
4763 DEBUG_VALID_MSG("Or succeeded");
4764 CONT = CONT->parent;
4765 DEPTH--;
4766 } else {
4767 DEBUG_VALID_MSG("Or failed");
4768 CONT = CONT->parent;
4769 DEPTH--;
4770 }
4771 break;
4772 case XML_ELEMENT_CONTENT_SEQ:
4773 if (ret == 0) {
4774 DEBUG_VALID_MSG("Sequence failed");
4775 CONT = CONT->parent;
4776 DEPTH--;
4777 } else if (CONT == CONT->parent->c1) {
4778 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4779 CONT = CONT->parent->c2;
4780 goto cont;
4781 } else {
4782 DEBUG_VALID_MSG("Sequence succeeded");
4783 CONT = CONT->parent;
4784 DEPTH--;
4785 }
4786 }
4787 }
4788 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004789 xmlNodePtr cur;
4790
4791 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004792 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4793 if (vstateVPop(ctxt) < 0 ) {
4794 DEBUG_VALID_MSG("exhaustion, failed");
4795 return(0);
4796 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004797 if (cur != ctxt->vstate->node)
4798 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004799 goto cont;
4800 }
4801 if (ret == 0) {
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("Failure, 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 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004814 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004815}
Daniel Veillard23e73572002-09-19 19:56:43 +00004816#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004817
4818/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00004819 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004820 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00004821 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004822 * @content: An element
4823 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4824 *
4825 * This will dump the list of elements to the buffer
4826 * Intended just for the debug routine
4827 */
4828static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00004829xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004830 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00004831 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004832
4833 if (node == NULL) return;
4834 if (glob) strcat(buf, "(");
4835 cur = node;
4836 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004837 len = strlen(buf);
4838 if (size - len < 50) {
4839 if ((size - len > 4) && (buf[len - 1] != '.'))
4840 strcat(buf, " ...");
4841 return;
4842 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004843 switch (cur->type) {
4844 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004845 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004846 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004847 if ((size - len > 4) && (buf[len - 1] != '.'))
4848 strcat(buf, " ...");
4849 return;
4850 }
4851 strcat(buf, (char *) cur->ns->prefix);
4852 strcat(buf, ":");
4853 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004854 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004855 if ((size - len > 4) && (buf[len - 1] != '.'))
4856 strcat(buf, " ...");
4857 return;
4858 }
4859 strcat(buf, (char *) cur->name);
4860 if (cur->next != NULL)
4861 strcat(buf, " ");
4862 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004863 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004864 if (xmlIsBlankNode(cur))
4865 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004866 case XML_CDATA_SECTION_NODE:
4867 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004868 strcat(buf, "CDATA");
4869 if (cur->next != NULL)
4870 strcat(buf, " ");
4871 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004872 case XML_ATTRIBUTE_NODE:
4873 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004874#ifdef LIBXML_DOCB_ENABLED
4875 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004876#endif
4877 case XML_HTML_DOCUMENT_NODE:
4878 case XML_DOCUMENT_TYPE_NODE:
4879 case XML_DOCUMENT_FRAG_NODE:
4880 case XML_NOTATION_NODE:
4881 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004882 strcat(buf, "???");
4883 if (cur->next != NULL)
4884 strcat(buf, " ");
4885 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004886 case XML_ENTITY_NODE:
4887 case XML_PI_NODE:
4888 case XML_DTD_NODE:
4889 case XML_COMMENT_NODE:
4890 case XML_ELEMENT_DECL:
4891 case XML_ATTRIBUTE_DECL:
4892 case XML_ENTITY_DECL:
4893 case XML_XINCLUDE_START:
4894 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004895 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004896 }
4897 cur = cur->next;
4898 }
4899 if (glob) strcat(buf, ")");
4900}
4901
4902/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004903 * xmlValidateElementContent:
4904 * @ctxt: the validation context
4905 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004906 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004907 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004908 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004909 *
4910 * Try to validate the content model of an element
4911 *
4912 * returns 1 if valid or 0 if not and -1 in case of error
4913 */
4914
4915static int
4916xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004917 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004918 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00004919#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00004920 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00004921#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00004922 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004923 xmlElementContentPtr cont;
4924 const xmlChar *name;
4925
4926 if (elemDecl == NULL)
4927 return(-1);
4928 cont = elemDecl->content;
4929 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004930
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004931#ifdef LIBXML_REGEXP_ENABLED
4932 /* Build the regexp associated to the content model */
4933 if (elemDecl->contModel == NULL)
4934 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4935 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004936 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004937 } else {
4938 xmlRegExecCtxtPtr exec;
4939
Daniel Veillardec498e12003-02-05 11:01:50 +00004940 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
4941 return(-1);
4942 }
Daniel Veillard01992e02002-10-09 10:20:30 +00004943 ctxt->nodeMax = 0;
4944 ctxt->nodeNr = 0;
4945 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004946 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4947 if (exec != NULL) {
4948 cur = child;
4949 while (cur != NULL) {
4950 switch (cur->type) {
4951 case XML_ENTITY_REF_NODE:
4952 /*
4953 * Push the current node to be able to roll back
4954 * and process within the entity
4955 */
4956 if ((cur->children != NULL) &&
4957 (cur->children->children != NULL)) {
4958 nodeVPush(ctxt, cur);
4959 cur = cur->children->children;
4960 continue;
4961 }
4962 break;
4963 case XML_TEXT_NODE:
4964 if (xmlIsBlankNode(cur))
4965 break;
4966 ret = 0;
4967 goto fail;
4968 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00004969 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004970 ret = 0;
4971 goto fail;
4972 case XML_ELEMENT_NODE:
4973 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004974 xmlChar fn[50];
4975 xmlChar *fullname;
4976
4977 fullname = xmlBuildQName(cur->name,
4978 cur->ns->prefix, fn, 50);
4979 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004980 ret = -1;
4981 goto fail;
4982 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004983 ret = xmlRegExecPushString(exec, fullname, NULL);
4984 if ((fullname != fn) && (fullname != cur->name))
4985 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004986 } else {
4987 ret = xmlRegExecPushString(exec, cur->name, NULL);
4988 }
4989 break;
4990 default:
4991 break;
4992 }
4993 /*
4994 * Switch to next element
4995 */
4996 cur = cur->next;
4997 while (cur == NULL) {
4998 cur = nodeVPop(ctxt);
4999 if (cur == NULL)
5000 break;
5001 cur = cur->next;
5002 }
5003 }
5004 ret = xmlRegExecPushString(exec, NULL, NULL);
5005fail:
5006 xmlRegFreeExecCtxt(exec);
5007 }
5008 }
5009#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005010 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005011 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005012 */
5013 ctxt->vstateMax = 8;
5014 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5015 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5016 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005017 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005018 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005019 }
5020 /*
5021 * The first entry in the stack is reserved to the current state
5022 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005023 ctxt->nodeMax = 0;
5024 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005025 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005026 ctxt->vstate = &ctxt->vstateTab[0];
5027 ctxt->vstateNr = 1;
5028 CONT = cont;
5029 NODE = child;
5030 DEPTH = 0;
5031 OCCURS = 0;
5032 STATE = 0;
5033 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005034 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005035 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5036 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005037 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005038 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005039 /*
5040 * An entities reference appeared at this level.
5041 * Buid a minimal representation of this node content
5042 * sufficient to run the validation process on it
5043 */
5044 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005045 cur = child;
5046 while (cur != NULL) {
5047 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005048 case XML_ENTITY_REF_NODE:
5049 /*
5050 * Push the current node to be able to roll back
5051 * and process within the entity
5052 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005053 if ((cur->children != NULL) &&
5054 (cur->children->children != NULL)) {
5055 nodeVPush(ctxt, cur);
5056 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005057 continue;
5058 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005059 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005060 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005061 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005062 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005063 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005064 case XML_CDATA_SECTION_NODE:
5065 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005066 case XML_ELEMENT_NODE:
5067 /*
5068 * Allocate a new node and minimally fills in
5069 * what's required
5070 */
5071 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5072 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005073 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005074 xmlFreeNodeList(repl);
5075 ret = -1;
5076 goto done;
5077 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005078 tmp->type = cur->type;
5079 tmp->name = cur->name;
5080 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005081 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005082 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005083 if (repl == NULL)
5084 repl = last = tmp;
5085 else {
5086 last->next = tmp;
5087 last = tmp;
5088 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005089 if (cur->type == XML_CDATA_SECTION_NODE) {
5090 /*
5091 * E59 spaces in CDATA does not match the
5092 * nonterminal S
5093 */
5094 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5095 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005096 break;
5097 default:
5098 break;
5099 }
5100 /*
5101 * Switch to next element
5102 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005103 cur = cur->next;
5104 while (cur == NULL) {
5105 cur = nodeVPop(ctxt);
5106 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005107 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005108 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005109 }
5110 }
5111
5112 /*
5113 * Relaunch the validation
5114 */
5115 ctxt->vstate = &ctxt->vstateTab[0];
5116 ctxt->vstateNr = 1;
5117 CONT = cont;
5118 NODE = repl;
5119 DEPTH = 0;
5120 OCCURS = 0;
5121 STATE = 0;
5122 ret = xmlValidateElementType(ctxt);
5123 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005124#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005125 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005126 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5127 char expr[5000];
5128 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005129
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005130 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005131 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005132 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005133#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005134 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005135 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005136 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005137#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005138 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005139
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005140 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005141 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5142 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5143 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005144 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005145 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5146 "Element content does not follow the DTD, expecting %s, got %s\n",
5147 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005148 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005149 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005150 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005151 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005152 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005153 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005154 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005155 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5156 "Element content does not follow the DTD\n",
5157 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005158 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005159 }
5160 ret = 0;
5161 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005162 if (ret == -3)
5163 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005164
Daniel Veillard23e73572002-09-19 19:56:43 +00005165#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005166done:
5167 /*
5168 * Deallocate the copy if done, and free up the validation stack
5169 */
5170 while (repl != NULL) {
5171 tmp = repl->next;
5172 xmlFree(repl);
5173 repl = tmp;
5174 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005175 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005176 if (ctxt->vstateTab != NULL) {
5177 xmlFree(ctxt->vstateTab);
5178 ctxt->vstateTab = NULL;
5179 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005180#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005181 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005182 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005183 if (ctxt->nodeTab != NULL) {
5184 xmlFree(ctxt->nodeTab);
5185 ctxt->nodeTab = NULL;
5186 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005187 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005188
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005189}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005190
Owen Taylor3473f882001-02-23 17:55:21 +00005191/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005192 * xmlValidateCdataElement:
5193 * @ctxt: the validation context
5194 * @doc: a document instance
5195 * @elem: an element instance
5196 *
5197 * Check that an element follows #CDATA
5198 *
5199 * returns 1 if valid or 0 otherwise
5200 */
5201static int
5202xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5203 xmlNodePtr elem) {
5204 int ret = 1;
5205 xmlNodePtr cur, child;
5206
Daniel Veillardceb09b92002-10-04 11:46:37 +00005207 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005208 return(0);
5209
5210 child = elem->children;
5211
5212 cur = child;
5213 while (cur != NULL) {
5214 switch (cur->type) {
5215 case XML_ENTITY_REF_NODE:
5216 /*
5217 * Push the current node to be able to roll back
5218 * and process within the entity
5219 */
5220 if ((cur->children != NULL) &&
5221 (cur->children->children != NULL)) {
5222 nodeVPush(ctxt, cur);
5223 cur = cur->children->children;
5224 continue;
5225 }
5226 break;
5227 case XML_COMMENT_NODE:
5228 case XML_PI_NODE:
5229 case XML_TEXT_NODE:
5230 case XML_CDATA_SECTION_NODE:
5231 break;
5232 default:
5233 ret = 0;
5234 goto done;
5235 }
5236 /*
5237 * Switch to next element
5238 */
5239 cur = cur->next;
5240 while (cur == NULL) {
5241 cur = nodeVPop(ctxt);
5242 if (cur == NULL)
5243 break;
5244 cur = cur->next;
5245 }
5246 }
5247done:
5248 ctxt->nodeMax = 0;
5249 ctxt->nodeNr = 0;
5250 if (ctxt->nodeTab != NULL) {
5251 xmlFree(ctxt->nodeTab);
5252 ctxt->nodeTab = NULL;
5253 }
5254 return(ret);
5255}
5256
5257/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005258 * xmlValidateCheckMixed:
5259 * @ctxt: the validation context
5260 * @cont: the mixed content model
5261 * @qname: the qualified name as appearing in the serialization
5262 *
5263 * Check if the given node is part of the content model.
5264 *
5265 * Returns 1 if yes, 0 if no, -1 in case of error
5266 */
5267static int
William M. Brackedb65a72004-02-06 07:36:04 +00005268xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005269 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005270 const xmlChar *name;
5271 int plen;
5272 name = xmlSplitQName3(qname, &plen);
5273
5274 if (name == NULL) {
5275 while (cont != NULL) {
5276 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5277 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5278 return(1);
5279 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5280 (cont->c1 != NULL) &&
5281 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5282 if ((cont->c1->prefix == NULL) &&
5283 (xmlStrEqual(cont->c1->name, qname)))
5284 return(1);
5285 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5286 (cont->c1 == NULL) ||
5287 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005288 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5289 "Internal: MIXED struct corrupted\n",
5290 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005291 break;
5292 }
5293 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005294 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005295 } else {
5296 while (cont != NULL) {
5297 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5298 if ((cont->prefix != NULL) &&
5299 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5300 (xmlStrEqual(cont->name, name)))
5301 return(1);
5302 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5303 (cont->c1 != NULL) &&
5304 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5305 if ((cont->c1->prefix != NULL) &&
5306 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5307 (xmlStrEqual(cont->c1->name, name)))
5308 return(1);
5309 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5310 (cont->c1 == NULL) ||
5311 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005312 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5313 "Internal: MIXED struct corrupted\n",
5314 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005315 break;
5316 }
5317 cont = cont->c2;
5318 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005319 }
5320 return(0);
5321}
5322
5323/**
5324 * xmlValidGetElemDecl:
5325 * @ctxt: the validation context
5326 * @doc: a document instance
5327 * @elem: an element instance
5328 * @extsubset: pointer, (out) indicate if the declaration was found
5329 * in the external subset.
5330 *
5331 * Finds a declaration associated to an element in the document.
5332 *
5333 * returns the pointer to the declaration or NULL if not found.
5334 */
5335static xmlElementPtr
5336xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5337 xmlNodePtr elem, int *extsubset) {
5338 xmlElementPtr elemDecl = NULL;
5339 const xmlChar *prefix = NULL;
5340
5341 if ((elem == NULL) || (elem->name == NULL)) return(NULL);
5342 if (extsubset != NULL)
5343 *extsubset = 0;
5344
5345 /*
5346 * Fetch the declaration for the qualified name
5347 */
5348 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5349 prefix = elem->ns->prefix;
5350
5351 if (prefix != NULL) {
5352 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5353 elem->name, prefix);
5354 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5355 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5356 elem->name, prefix);
5357 if ((elemDecl != NULL) && (extsubset != NULL))
5358 *extsubset = 1;
5359 }
5360 }
5361
5362 /*
5363 * Fetch the declaration for the non qualified name
5364 * This is "non-strict" validation should be done on the
5365 * full QName but in that case being flexible makes sense.
5366 */
5367 if (elemDecl == NULL) {
5368 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5369 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5370 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5371 if ((elemDecl != NULL) && (extsubset != NULL))
5372 *extsubset = 1;
5373 }
5374 }
5375 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005376 xmlErrValidNode(ctxt, elem,
5377 XML_DTD_UNKNOWN_ELEM,
5378 "No declaration for element %s\n",
5379 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005380 }
5381 return(elemDecl);
5382}
5383
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005384#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005385/**
5386 * xmlValidatePushElement:
5387 * @ctxt: the validation context
5388 * @doc: a document instance
5389 * @elem: an element instance
5390 * @qname: the qualified name as appearing in the serialization
5391 *
5392 * Push a new element start on the validation stack.
5393 *
5394 * returns 1 if no validation problem was found or 0 otherwise
5395 */
5396int
5397xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5398 xmlNodePtr elem, const xmlChar *qname) {
5399 int ret = 1;
5400 xmlElementPtr eDecl;
5401 int extsubset = 0;
5402
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005403/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005404 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5405 xmlValidStatePtr state = ctxt->vstate;
5406 xmlElementPtr elemDecl;
5407
5408 /*
5409 * Check the new element agaisnt the content model of the new elem.
5410 */
5411 if (state->elemDecl != NULL) {
5412 elemDecl = state->elemDecl;
5413
5414 switch(elemDecl->etype) {
5415 case XML_ELEMENT_TYPE_UNDEFINED:
5416 ret = 0;
5417 break;
5418 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005419 xmlErrValidNode(ctxt, state->node,
5420 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005421 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005422 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005423 ret = 0;
5424 break;
5425 case XML_ELEMENT_TYPE_ANY:
5426 /* I don't think anything is required then */
5427 break;
5428 case XML_ELEMENT_TYPE_MIXED:
5429 /* simple case of declared as #PCDATA */
5430 if ((elemDecl->content != NULL) &&
5431 (elemDecl->content->type ==
5432 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005433 xmlErrValidNode(ctxt, state->node,
5434 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005435 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005436 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005437 ret = 0;
5438 } else {
5439 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5440 qname);
5441 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005442 xmlErrValidNode(ctxt, state->node,
5443 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005444 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005445 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005446 }
5447 }
5448 break;
5449 case XML_ELEMENT_TYPE_ELEMENT:
5450 /*
5451 * TODO:
5452 * VC: Standalone Document Declaration
5453 * - element types with element content, if white space
5454 * occurs directly within any instance of those types.
5455 */
5456 if (state->exec != NULL) {
5457 ret = xmlRegExecPushString(state->exec, qname, NULL);
5458 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005459 xmlErrValidNode(ctxt, state->node,
5460 XML_DTD_CONTENT_MODEL,
5461 "Element %s content does not follow the DTD, Misplaced %s\n",
5462 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005463 ret = 0;
5464 } else {
5465 ret = 1;
5466 }
5467 }
5468 break;
5469 }
5470 }
5471 }
5472 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5473 vstateVPush(ctxt, eDecl, elem);
5474 return(ret);
5475}
5476
5477/**
5478 * xmlValidatePushCData:
5479 * @ctxt: the validation context
5480 * @data: some character data read
5481 * @len: the lenght of the data
5482 *
5483 * check the CData parsed for validation in the current stack
5484 *
5485 * returns 1 if no validation problem was found or 0 otherwise
5486 */
5487int
5488xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5489 int ret = 1;
5490
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005491/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005492 if (len <= 0)
5493 return(ret);
5494 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5495 xmlValidStatePtr state = ctxt->vstate;
5496 xmlElementPtr elemDecl;
5497
5498 /*
5499 * Check the new element agaisnt the content model of the new elem.
5500 */
5501 if (state->elemDecl != NULL) {
5502 elemDecl = state->elemDecl;
5503
5504 switch(elemDecl->etype) {
5505 case XML_ELEMENT_TYPE_UNDEFINED:
5506 ret = 0;
5507 break;
5508 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005509 xmlErrValidNode(ctxt, state->node,
5510 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005511 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005512 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005513 ret = 0;
5514 break;
5515 case XML_ELEMENT_TYPE_ANY:
5516 break;
5517 case XML_ELEMENT_TYPE_MIXED:
5518 break;
5519 case XML_ELEMENT_TYPE_ELEMENT:
5520 if (len > 0) {
5521 int i;
5522
5523 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005524 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005525 xmlErrValidNode(ctxt, state->node,
5526 XML_DTD_CONTENT_MODEL,
5527 "Element %s content does not follow the DTD, Text not allowed\n",
5528 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005529 ret = 0;
5530 goto done;
5531 }
5532 }
5533 /*
5534 * TODO:
5535 * VC: Standalone Document Declaration
5536 * element types with element content, if white space
5537 * occurs directly within any instance of those types.
5538 */
5539 }
5540 break;
5541 }
5542 }
5543 }
5544done:
5545 return(ret);
5546}
5547
5548/**
5549 * xmlValidatePopElement:
5550 * @ctxt: the validation context
5551 * @doc: a document instance
5552 * @elem: an element instance
5553 * @qname: the qualified name as appearing in the serialization
5554 *
5555 * Pop the element end from the validation stack.
5556 *
5557 * returns 1 if no validation problem was found or 0 otherwise
5558 */
5559int
5560xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005561 xmlNodePtr elem ATTRIBUTE_UNUSED,
5562 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005563 int ret = 1;
5564
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005565/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005566 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5567 xmlValidStatePtr state = ctxt->vstate;
5568 xmlElementPtr elemDecl;
5569
5570 /*
5571 * Check the new element agaisnt the content model of the new elem.
5572 */
5573 if (state->elemDecl != NULL) {
5574 elemDecl = state->elemDecl;
5575
5576 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5577 if (state->exec != NULL) {
5578 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5579 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005580 xmlErrValidNode(ctxt, state->node,
5581 XML_DTD_CONTENT_MODEL,
5582 "Element %s content does not follow the DTD, Expecting more child\n",
5583 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005584 } else {
5585 /*
5586 * previous validation errors should not generate
5587 * a new one here
5588 */
5589 ret = 1;
5590 }
5591 }
5592 }
5593 }
5594 vstateVPop(ctxt);
5595 }
5596 return(ret);
5597}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005598#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005599
5600/**
Owen Taylor3473f882001-02-23 17:55:21 +00005601 * xmlValidateOneElement:
5602 * @ctxt: the validation context
5603 * @doc: a document instance
5604 * @elem: an element instance
5605 *
5606 * Try to validate a single element and it's attributes,
5607 * basically it does the following checks as described by the
5608 * XML-1.0 recommendation:
5609 * - [ VC: Element Valid ]
5610 * - [ VC: Required Attribute ]
5611 * Then call xmlValidateOneAttribute() for each attribute present.
5612 *
5613 * The ID/IDREF checkings are done separately
5614 *
5615 * returns 1 if valid or 0 otherwise
5616 */
5617
5618int
5619xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5620 xmlNodePtr elem) {
5621 xmlElementPtr elemDecl = NULL;
5622 xmlElementContentPtr cont;
5623 xmlAttributePtr attr;
5624 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005625 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005626 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005627 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005628
5629 CHECK_DTD;
5630
5631 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005632 switch (elem->type) {
5633 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005634 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5635 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005636 return(0);
5637 case XML_TEXT_NODE:
5638 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005639 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5640 "Text element has children !\n",
5641 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005642 return(0);
5643 }
5644 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005645 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5646 "Text element has attribute !\n",
5647 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005648 return(0);
5649 }
5650 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005651 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5652 "Text element has namespace !\n",
5653 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005654 return(0);
5655 }
5656 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005657 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5658 "Text element has namespace !\n",
5659 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005660 return(0);
5661 }
5662 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005663 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5664 "Text element has no content !\n",
5665 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005666 return(0);
5667 }
5668 return(1);
5669 case XML_XINCLUDE_START:
5670 case XML_XINCLUDE_END:
5671 return(1);
5672 case XML_CDATA_SECTION_NODE:
5673 case XML_ENTITY_REF_NODE:
5674 case XML_PI_NODE:
5675 case XML_COMMENT_NODE:
5676 return(1);
5677 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005678 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5679 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005680 return(0);
5681 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005682 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5683 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005684 return(0);
5685 case XML_DOCUMENT_NODE:
5686 case XML_DOCUMENT_TYPE_NODE:
5687 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005688 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5689 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005690 return(0);
5691 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005692 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5693 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005694 return(0);
5695 case XML_ELEMENT_NODE:
5696 break;
5697 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005698 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5699 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005700 return(0);
5701 }
Owen Taylor3473f882001-02-23 17:55:21 +00005702
5703 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005704 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005705 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005706 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5707 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005708 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005709
Daniel Veillardea7751d2002-12-20 00:16:24 +00005710 /*
5711 * If vstateNr is not zero that means continuous validation is
5712 * activated, do not try to check the content model at that level.
5713 */
5714 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005715 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005716 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005717 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005718 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5719 "No declaration for element %s\n",
5720 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005721 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005722 case XML_ELEMENT_TYPE_EMPTY:
5723 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005724 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005725 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005726 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005727 ret = 0;
5728 }
5729 break;
5730 case XML_ELEMENT_TYPE_ANY:
5731 /* I don't think anything is required then */
5732 break;
5733 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005734
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005735 /* simple case of declared as #PCDATA */
5736 if ((elemDecl->content != NULL) &&
5737 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5738 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5739 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005740 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005741 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005742 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005743 }
5744 break;
5745 }
Owen Taylor3473f882001-02-23 17:55:21 +00005746 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005747 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005748 while (child != NULL) {
5749 if (child->type == XML_ELEMENT_NODE) {
5750 name = child->name;
5751 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005752 xmlChar fn[50];
5753 xmlChar *fullname;
5754
5755 fullname = xmlBuildQName(child->name, child->ns->prefix,
5756 fn, 50);
5757 if (fullname == NULL)
5758 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005759 cont = elemDecl->content;
5760 while (cont != NULL) {
5761 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005762 if (xmlStrEqual(cont->name, fullname))
5763 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005764 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5765 (cont->c1 != NULL) &&
5766 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005767 if (xmlStrEqual(cont->c1->name, fullname))
5768 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005769 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5770 (cont->c1 == NULL) ||
5771 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005772 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5773 "Internal: MIXED struct corrupted\n",
5774 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005775 break;
5776 }
5777 cont = cont->c2;
5778 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005779 if ((fullname != fn) && (fullname != child->name))
5780 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005781 if (cont != NULL)
5782 goto child_ok;
5783 }
5784 cont = elemDecl->content;
5785 while (cont != NULL) {
5786 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5787 if (xmlStrEqual(cont->name, name)) break;
5788 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5789 (cont->c1 != NULL) &&
5790 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5791 if (xmlStrEqual(cont->c1->name, name)) break;
5792 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5793 (cont->c1 == NULL) ||
5794 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005795 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5796 "Internal: MIXED struct corrupted\n",
5797 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005798 break;
5799 }
5800 cont = cont->c2;
5801 }
5802 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005803 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00005804 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005805 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005806 ret = 0;
5807 }
5808 }
5809child_ok:
5810 child = child->next;
5811 }
5812 break;
5813 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005814 if ((doc->standalone == 1) && (extsubset == 1)) {
5815 /*
5816 * VC: Standalone Document Declaration
5817 * - element types with element content, if white space
5818 * occurs directly within any instance of those types.
5819 */
5820 child = elem->children;
5821 while (child != NULL) {
5822 if (child->type == XML_TEXT_NODE) {
5823 const xmlChar *content = child->content;
5824
William M. Brack76e95df2003-10-18 16:20:14 +00005825 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005826 content++;
5827 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005828 xmlErrValidNode(ctxt, elem,
5829 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005830"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005831 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005832 ret = 0;
5833 break;
5834 }
5835 }
5836 child =child->next;
5837 }
5838 }
Owen Taylor3473f882001-02-23 17:55:21 +00005839 child = elem->children;
5840 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005841 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005842 if (tmp <= 0)
5843 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005844 break;
5845 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005846 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00005847
5848 /* [ VC: Required Attribute ] */
5849 attr = elemDecl->attributes;
5850 while (attr != NULL) {
5851 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005852 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005853
Daniel Veillarde4301c82002-02-13 13:32:35 +00005854 if ((attr->prefix == NULL) &&
5855 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5856 xmlNsPtr ns;
5857
5858 ns = elem->nsDef;
5859 while (ns != NULL) {
5860 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005861 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005862 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00005863 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005864 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5865 xmlNsPtr ns;
5866
5867 ns = elem->nsDef;
5868 while (ns != NULL) {
5869 if (xmlStrEqual(attr->name, ns->prefix))
5870 goto found;
5871 ns = ns->next;
5872 }
5873 } else {
5874 xmlAttrPtr attrib;
5875
5876 attrib = elem->properties;
5877 while (attrib != NULL) {
5878 if (xmlStrEqual(attrib->name, attr->name)) {
5879 if (attr->prefix != NULL) {
5880 xmlNsPtr nameSpace = attrib->ns;
5881
5882 if (nameSpace == NULL)
5883 nameSpace = elem->ns;
5884 /*
5885 * qualified names handling is problematic, having a
5886 * different prefix should be possible but DTDs don't
5887 * allow to define the URI instead of the prefix :-(
5888 */
5889 if (nameSpace == NULL) {
5890 if (qualified < 0)
5891 qualified = 0;
5892 } else if (!xmlStrEqual(nameSpace->prefix,
5893 attr->prefix)) {
5894 if (qualified < 1)
5895 qualified = 1;
5896 } else
5897 goto found;
5898 } else {
5899 /*
5900 * We should allow applications to define namespaces
5901 * for their application even if the DTD doesn't
5902 * carry one, otherwise, basically we would always
5903 * break.
5904 */
5905 goto found;
5906 }
5907 }
5908 attrib = attrib->next;
5909 }
Owen Taylor3473f882001-02-23 17:55:21 +00005910 }
5911 if (qualified == -1) {
5912 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005913 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005914 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005915 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005916 ret = 0;
5917 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005918 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005919 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005920 elem->name, attr->prefix,attr->name);
5921 ret = 0;
5922 }
5923 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005924 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005925 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005926 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005927 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005928 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005929 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005930 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005931 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005932 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5933 /*
5934 * Special tests checking #FIXED namespace declarations
5935 * have the right value since this is not done as an
5936 * attribute checking
5937 */
5938 if ((attr->prefix == NULL) &&
5939 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5940 xmlNsPtr ns;
5941
5942 ns = elem->nsDef;
5943 while (ns != NULL) {
5944 if (ns->prefix == NULL) {
5945 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005946 xmlErrValidNode(ctxt, elem,
5947 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00005948 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005949 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005950 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005951 }
5952 goto found;
5953 }
5954 ns = ns->next;
5955 }
5956 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5957 xmlNsPtr ns;
5958
5959 ns = elem->nsDef;
5960 while (ns != NULL) {
5961 if (xmlStrEqual(attr->name, ns->prefix)) {
5962 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005963 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005964 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005965 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005966 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005967 }
5968 goto found;
5969 }
5970 ns = ns->next;
5971 }
5972 }
Owen Taylor3473f882001-02-23 17:55:21 +00005973 }
5974found:
5975 attr = attr->nexth;
5976 }
5977 return(ret);
5978}
5979
5980/**
5981 * xmlValidateRoot:
5982 * @ctxt: the validation context
5983 * @doc: a document instance
5984 *
5985 * Try to validate a the root element
5986 * basically it does the following check as described by the
5987 * XML-1.0 recommendation:
5988 * - [ VC: Root Element Type ]
5989 * it doesn't try to recurse or apply other check to the element
5990 *
5991 * returns 1 if valid or 0 otherwise
5992 */
5993
5994int
5995xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
5996 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00005997 int ret;
5998
Owen Taylor3473f882001-02-23 17:55:21 +00005999 if (doc == NULL) return(0);
6000
6001 root = xmlDocGetRootElement(doc);
6002 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006003 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6004 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006005 return(0);
6006 }
6007
6008 /*
6009 * When doing post validation against a separate DTD, those may
6010 * no internal subset has been generated
6011 */
6012 if ((doc->intSubset != NULL) &&
6013 (doc->intSubset->name != NULL)) {
6014 /*
6015 * Check first the document root against the NQName
6016 */
6017 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6018 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006019 xmlChar fn[50];
6020 xmlChar *fullname;
6021
6022 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6023 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006024 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006025 return(0);
6026 }
6027 ret = xmlStrEqual(doc->intSubset->name, fullname);
6028 if ((fullname != fn) && (fullname != root->name))
6029 xmlFree(fullname);
6030 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006031 goto name_ok;
6032 }
6033 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6034 (xmlStrEqual(root->name, BAD_CAST "html")))
6035 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006036 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6037 "root and DTD name do not match '%s' and '%s'\n",
6038 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006039 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006040 }
6041 }
6042name_ok:
6043 return(1);
6044}
6045
6046
6047/**
6048 * xmlValidateElement:
6049 * @ctxt: the validation context
6050 * @doc: a document instance
6051 * @elem: an element instance
6052 *
6053 * Try to validate the subtree under an element
6054 *
6055 * returns 1 if valid or 0 otherwise
6056 */
6057
6058int
6059xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6060 xmlNodePtr child;
6061 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006062 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006063 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006064 int ret = 1;
6065
6066 if (elem == NULL) return(0);
6067
6068 /*
6069 * XInclude elements were added after parsing in the infoset,
6070 * they don't really mean anything validation wise.
6071 */
6072 if ((elem->type == XML_XINCLUDE_START) ||
6073 (elem->type == XML_XINCLUDE_END))
6074 return(1);
6075
6076 CHECK_DTD;
6077
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006078 /*
6079 * Entities references have to be handled separately
6080 */
6081 if (elem->type == XML_ENTITY_REF_NODE) {
6082 return(1);
6083 }
6084
Owen Taylor3473f882001-02-23 17:55:21 +00006085 ret &= xmlValidateOneElement(ctxt, doc, elem);
6086 attr = elem->properties;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006087 while (attr != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006088 value = xmlNodeListGetString(doc, attr->children, 0);
6089 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6090 if (value != NULL)
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006091 xmlFree((char *)value);
Owen Taylor3473f882001-02-23 17:55:21 +00006092 attr= attr->next;
6093 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006094 ns = elem->nsDef;
6095 while (ns != NULL) {
Daniel Veillard1f5c9892003-12-29 17:09:55 +00006096 if (elem->ns == NULL)
6097 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6098 ns, ns->href);
6099 else
6100 ret &= xmlValidateOneNamespace(ctxt, doc, elem, elem->ns->prefix,
6101 ns, ns->href);
Daniel Veillarde133dd82003-10-30 10:42:20 +00006102 ns = ns->next;
6103 }
Owen Taylor3473f882001-02-23 17:55:21 +00006104 child = elem->children;
6105 while (child != NULL) {
6106 ret &= xmlValidateElement(ctxt, doc, child);
6107 child = child->next;
6108 }
6109
6110 return(ret);
6111}
6112
Daniel Veillard8730c562001-02-26 10:49:57 +00006113/**
6114 * xmlValidateRef:
6115 * @ref: A reference to be validated
6116 * @ctxt: Validation context
6117 * @name: Name of ID we are searching for
6118 *
6119 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006120static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006121xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006122 const xmlChar *name) {
6123 xmlAttrPtr id;
6124 xmlAttrPtr attr;
6125
6126 if (ref == NULL)
6127 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006128 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006129 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006130 attr = ref->attr;
6131 if (attr == NULL) {
6132 xmlChar *dup, *str = NULL, *cur, save;
6133
6134 dup = xmlStrdup(name);
6135 if (dup == NULL) {
6136 ctxt->valid = 0;
6137 return;
6138 }
6139 cur = dup;
6140 while (*cur != 0) {
6141 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006142 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006143 save = *cur;
6144 *cur = 0;
6145 id = xmlGetID(ctxt->doc, str);
6146 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006147 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006148 "attribute %s line %d references an unknown ID \"%s\"\n",
6149 ref->name, ref->lineno, str);
6150 ctxt->valid = 0;
6151 }
6152 if (save == 0)
6153 break;
6154 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006155 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006156 }
6157 xmlFree(dup);
6158 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006159 id = xmlGetID(ctxt->doc, name);
6160 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006161 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006162 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006163 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006164 ctxt->valid = 0;
6165 }
6166 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6167 xmlChar *dup, *str = NULL, *cur, save;
6168
6169 dup = xmlStrdup(name);
6170 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006171 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006172 ctxt->valid = 0;
6173 return;
6174 }
6175 cur = dup;
6176 while (*cur != 0) {
6177 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006178 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006179 save = *cur;
6180 *cur = 0;
6181 id = xmlGetID(ctxt->doc, str);
6182 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006183 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006184 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006185 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006186 ctxt->valid = 0;
6187 }
6188 if (save == 0)
6189 break;
6190 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006191 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006192 }
6193 xmlFree(dup);
6194 }
6195}
6196
6197/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006198 * xmlWalkValidateList:
6199 * @data: Contents of current link
6200 * @user: Value supplied by the user
6201 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006202 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006203 */
6204static int
6205xmlWalkValidateList(const void *data, const void *user)
6206{
6207 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6208 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6209 return 1;
6210}
6211
6212/**
6213 * xmlValidateCheckRefCallback:
6214 * @ref_list: List of references
6215 * @ctxt: Validation context
6216 * @name: Name of ID we are searching for
6217 *
6218 */
6219static void
6220xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6221 const xmlChar *name) {
6222 xmlValidateMemo memo;
6223
6224 if (ref_list == NULL)
6225 return;
6226 memo.ctxt = ctxt;
6227 memo.name = name;
6228
6229 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6230
6231}
6232
6233/**
Owen Taylor3473f882001-02-23 17:55:21 +00006234 * xmlValidateDocumentFinal:
6235 * @ctxt: the validation context
6236 * @doc: a document instance
6237 *
6238 * Does the final step for the document validation once all the
6239 * incremental validation steps have been completed
6240 *
6241 * basically it does the following checks described by the XML Rec
6242 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006243 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006244 *
6245 * returns 1 if valid or 0 otherwise
6246 */
6247
6248int
6249xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6250 xmlRefTablePtr table;
6251
6252 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006253 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6254 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006255 return(0);
6256 }
6257
6258 /*
6259 * Check all the NOTATION/NOTATIONS attributes
6260 */
6261 /*
6262 * Check all the ENTITY/ENTITIES attributes definition for validity
6263 */
6264 /*
6265 * Check all the IDREF/IDREFS attributes definition for validity
6266 */
6267 table = (xmlRefTablePtr) doc->refs;
6268 ctxt->doc = doc;
6269 ctxt->valid = 1;
6270 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6271 return(ctxt->valid);
6272}
6273
6274/**
6275 * xmlValidateDtd:
6276 * @ctxt: the validation context
6277 * @doc: a document instance
6278 * @dtd: a dtd instance
6279 *
6280 * Try to validate the document against the dtd instance
6281 *
6282 * basically it does check all the definitions in the DtD.
6283 *
6284 * returns 1 if valid or 0 otherwise
6285 */
6286
6287int
6288xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6289 int ret;
6290 xmlDtdPtr oldExt;
6291 xmlNodePtr root;
6292
6293 if (dtd == NULL) return(0);
6294 if (doc == NULL) return(0);
6295 oldExt = doc->extSubset;
6296 doc->extSubset = dtd;
6297 ret = xmlValidateRoot(ctxt, doc);
6298 if (ret == 0) {
6299 doc->extSubset = oldExt;
6300 return(ret);
6301 }
6302 if (doc->ids != NULL) {
6303 xmlFreeIDTable(doc->ids);
6304 doc->ids = NULL;
6305 }
6306 if (doc->refs != NULL) {
6307 xmlFreeRefTable(doc->refs);
6308 doc->refs = NULL;
6309 }
6310 root = xmlDocGetRootElement(doc);
6311 ret = xmlValidateElement(ctxt, doc, root);
6312 ret &= xmlValidateDocumentFinal(ctxt, doc);
6313 doc->extSubset = oldExt;
6314 return(ret);
6315}
6316
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006317static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006318xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6319 const xmlChar *name ATTRIBUTE_UNUSED) {
6320 if (cur == NULL)
6321 return;
6322 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6323 xmlChar *notation = cur->content;
6324
Daniel Veillard878eab02002-02-19 13:46:09 +00006325 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006326 int ret;
6327
6328 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6329 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006330 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006331 }
6332 }
6333 }
6334}
6335
6336static void
Owen Taylor3473f882001-02-23 17:55:21 +00006337xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006338 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006339 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006340 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006341 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006342
Owen Taylor3473f882001-02-23 17:55:21 +00006343 if (cur == NULL)
6344 return;
6345 switch (cur->atype) {
6346 case XML_ATTRIBUTE_CDATA:
6347 case XML_ATTRIBUTE_ID:
6348 case XML_ATTRIBUTE_IDREF :
6349 case XML_ATTRIBUTE_IDREFS:
6350 case XML_ATTRIBUTE_NMTOKEN:
6351 case XML_ATTRIBUTE_NMTOKENS:
6352 case XML_ATTRIBUTE_ENUMERATION:
6353 break;
6354 case XML_ATTRIBUTE_ENTITY:
6355 case XML_ATTRIBUTE_ENTITIES:
6356 case XML_ATTRIBUTE_NOTATION:
6357 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006358
6359 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6360 cur->atype, cur->defaultValue);
6361 if ((ret == 0) && (ctxt->valid == 1))
6362 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006363 }
6364 if (cur->tree != NULL) {
6365 xmlEnumerationPtr tree = cur->tree;
6366 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006367 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006368 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006369 if ((ret == 0) && (ctxt->valid == 1))
6370 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006371 tree = tree->next;
6372 }
6373 }
6374 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006375 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6376 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006377 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006378 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006379 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006380 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006381 return;
6382 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006383
6384 if (doc != NULL)
6385 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6386 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006387 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006388 if ((elem == NULL) && (cur->parent != NULL) &&
6389 (cur->parent->type == XML_DTD_NODE))
6390 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006391 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006392 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006393 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006394 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006395 return;
6396 }
6397 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006398 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006399 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006400 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006401 ctxt->valid = 0;
6402 }
6403 }
Owen Taylor3473f882001-02-23 17:55:21 +00006404}
6405
6406/**
6407 * xmlValidateDtdFinal:
6408 * @ctxt: the validation context
6409 * @doc: a document instance
6410 *
6411 * Does the final step for the dtds validation once all the
6412 * subsets have been parsed
6413 *
6414 * basically it does the following checks described by the XML Rec
6415 * - check that ENTITY and ENTITIES type attributes default or
6416 * possible values matches one of the defined entities.
6417 * - check that NOTATION type attributes default or
6418 * possible values matches one of the defined notations.
6419 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006420 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006421 */
6422
6423int
6424xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006425 xmlDtdPtr dtd;
6426 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006427 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006428
6429 if (doc == NULL) return(0);
6430 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6431 return(0);
6432 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006433 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006434 dtd = doc->intSubset;
6435 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6436 table = (xmlAttributeTablePtr) dtd->attributes;
6437 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006438 }
6439 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006440 entities = (xmlEntitiesTablePtr) dtd->entities;
6441 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6442 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006443 }
6444 dtd = doc->extSubset;
6445 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6446 table = (xmlAttributeTablePtr) dtd->attributes;
6447 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006448 }
6449 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006450 entities = (xmlEntitiesTablePtr) dtd->entities;
6451 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6452 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006453 }
6454 return(ctxt->valid);
6455}
6456
6457/**
6458 * xmlValidateDocument:
6459 * @ctxt: the validation context
6460 * @doc: a document instance
6461 *
6462 * Try to validate the document instance
6463 *
6464 * basically it does the all the checks described by the XML Rec
6465 * i.e. validates the internal and external subset (if present)
6466 * and validate the document tree.
6467 *
6468 * returns 1 if valid or 0 otherwise
6469 */
6470
6471int
6472xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6473 int ret;
6474 xmlNodePtr root;
6475
Daniel Veillard2fd85422002-10-16 14:32:41 +00006476 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006477 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6478 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006479 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006480 }
Owen Taylor3473f882001-02-23 17:55:21 +00006481 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6482 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6483 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6484 doc->intSubset->SystemID);
6485 if (doc->extSubset == NULL) {
6486 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006487 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006488 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006489 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006490 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006491 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006492 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006493 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006494 }
6495 return(0);
6496 }
6497 }
6498
6499 if (doc->ids != NULL) {
6500 xmlFreeIDTable(doc->ids);
6501 doc->ids = NULL;
6502 }
6503 if (doc->refs != NULL) {
6504 xmlFreeRefTable(doc->refs);
6505 doc->refs = NULL;
6506 }
6507 ret = xmlValidateDtdFinal(ctxt, doc);
6508 if (!xmlValidateRoot(ctxt, doc)) return(0);
6509
6510 root = xmlDocGetRootElement(doc);
6511 ret &= xmlValidateElement(ctxt, doc, root);
6512 ret &= xmlValidateDocumentFinal(ctxt, doc);
6513 return(ret);
6514}
6515
Owen Taylor3473f882001-02-23 17:55:21 +00006516/************************************************************************
6517 * *
6518 * Routines for dynamic validation editing *
6519 * *
6520 ************************************************************************/
6521
6522/**
6523 * xmlValidGetPotentialChildren:
6524 * @ctree: an element content tree
6525 * @list: an array to store the list of child names
6526 * @len: a pointer to the number of element in the list
6527 * @max: the size of the array
6528 *
6529 * Build/extend a list of potential children allowed by the content tree
6530 *
6531 * returns the number of element in the list, or -1 in case of error.
6532 */
6533
6534int
6535xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6536 int *len, int max) {
6537 int i;
6538
6539 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6540 return(-1);
6541 if (*len >= max) return(*len);
6542
6543 switch (ctree->type) {
6544 case XML_ELEMENT_CONTENT_PCDATA:
6545 for (i = 0; i < *len;i++)
6546 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6547 list[(*len)++] = BAD_CAST "#PCDATA";
6548 break;
6549 case XML_ELEMENT_CONTENT_ELEMENT:
6550 for (i = 0; i < *len;i++)
6551 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6552 list[(*len)++] = ctree->name;
6553 break;
6554 case XML_ELEMENT_CONTENT_SEQ:
6555 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6556 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6557 break;
6558 case XML_ELEMENT_CONTENT_OR:
6559 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6560 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6561 break;
6562 }
6563
6564 return(*len);
6565}
6566
6567/**
6568 * xmlValidGetValidElements:
6569 * @prev: an element to insert after
6570 * @next: an element to insert next
6571 * @list: an array to store the list of child names
6572 * @max: the size of the array
6573 *
6574 * This function returns the list of authorized children to insert
6575 * within an existing tree while respecting the validity constraints
6576 * forced by the Dtd. The insertion point is defined using @prev and
6577 * @next in the following ways:
6578 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6579 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6580 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6581 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6582 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6583 *
6584 * pointers to the element names are inserted at the beginning of the array
6585 * and do not need to be freed.
6586 *
6587 * returns the number of element in the list, or -1 in case of error. If
6588 * the function returns the value @max the caller is invited to grow the
6589 * receiving array and retry.
6590 */
6591
6592int
6593xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
6594 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006595 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006596 int nb_valid_elements = 0;
6597 const xmlChar *elements[256];
6598 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006599 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006600
6601 xmlNode *ref_node;
6602 xmlNode *parent;
6603 xmlNode *test_node;
6604
6605 xmlNode *prev_next;
6606 xmlNode *next_prev;
6607 xmlNode *parent_childs;
6608 xmlNode *parent_last;
6609
6610 xmlElement *element_desc;
6611
Daniel Veillardbb4e46d2002-03-10 16:49:08 +00006612 memset(&vctxt, 0, sizeof (xmlValidCtxt));
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006613
Owen Taylor3473f882001-02-23 17:55:21 +00006614 if (prev == NULL && next == NULL)
6615 return(-1);
6616
6617 if (list == NULL) return(-1);
6618 if (max <= 0) return(-1);
6619
6620 nb_valid_elements = 0;
6621 ref_node = prev ? prev : next;
6622 parent = ref_node->parent;
6623
6624 /*
6625 * Retrieves the parent element declaration
6626 */
6627 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6628 parent->name);
6629 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6630 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6631 parent->name);
6632 if (element_desc == NULL) return(-1);
6633
6634 /*
6635 * Do a backup of the current tree structure
6636 */
6637 prev_next = prev ? prev->next : NULL;
6638 next_prev = next ? next->prev : NULL;
6639 parent_childs = parent->children;
6640 parent_last = parent->last;
6641
6642 /*
6643 * Creates a dummy node and insert it into the tree
6644 */
6645 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
6646 test_node->doc = ref_node->doc;
6647 test_node->parent = parent;
6648 test_node->prev = prev;
6649 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006650 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006651
6652 if (prev) prev->next = test_node;
6653 else parent->children = test_node;
6654
6655 if (next) next->prev = test_node;
6656 else parent->last = test_node;
6657
6658 /*
6659 * Insert each potential child node and check if the parent is
6660 * still valid
6661 */
6662 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6663 elements, &nb_elements, 256);
6664
6665 for (i = 0;i < nb_elements;i++) {
6666 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006667 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006668 int j;
6669
6670 for (j = 0; j < nb_valid_elements;j++)
6671 if (xmlStrEqual(elements[i], list[j])) break;
6672 list[nb_valid_elements++] = elements[i];
6673 if (nb_valid_elements >= max) break;
6674 }
6675 }
6676
6677 /*
6678 * Restore the tree structure
6679 */
6680 if (prev) prev->next = prev_next;
6681 if (next) next->prev = next_prev;
6682 parent->children = parent_childs;
6683 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006684
6685 /*
6686 * Free up the dummy node
6687 */
6688 test_node->name = name;
6689 xmlFreeNode(test_node);
6690
Owen Taylor3473f882001-02-23 17:55:21 +00006691 return(nb_valid_elements);
6692}
Daniel Veillard4432df22003-09-28 18:58:27 +00006693#endif /* LIBXML_VALID_ENABLED */
6694