blob: 1844ad21931e23183aceceb07d2c9de50e0bf451 [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 Veillardf54cd532004-02-25 11:52:31 +0000108#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
109/**
110 * xmlErrValidNode:
111 * @ctxt: an XML validation parser context
112 * @node: the node raising the error
113 * @error: the error number
114 * @str1: extra informations
115 * @str2: extra informations
116 * @str3: extra informations
117 *
118 * Handle a validation error, provide contextual informations
119 */
120static void
121xmlErrValidNode(xmlValidCtxtPtr ctxt,
122 xmlNodePtr node, xmlParserErrors error,
123 const char *msg, const xmlChar * str1,
124 const xmlChar * str2, const xmlChar * str3)
125{
126 xmlStructuredErrorFunc schannel = NULL;
127 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 }
136 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
137 XML_ERR_ERROR, NULL, 0,
138 (const char *) str1,
139 (const char *) str1,
140 (const char *) str3, 0, 0, msg, str1, str2, str3);
141}
142#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
143
Daniel Veillardd61e8fb2003-10-19 21:59:17 +0000144#ifdef LIBXML_VALID_ENABLED
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000145/**
146 * xmlErrValidNodeNr:
147 * @ctxt: an XML validation parser context
148 * @node: the node raising the error
149 * @error: the error number
150 * @str1: extra informations
151 * @int2: extra informations
152 * @str3: extra informations
153 *
154 * Handle a validation error, provide contextual informations
155 */
156static void
Daniel Veillard72b9e292003-10-28 15:44:17 +0000157xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000158 xmlNodePtr node, xmlParserErrors error,
159 const char *msg, const xmlChar * str1,
160 int int2, const xmlChar * str3)
161{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000162 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000163 xmlGenericErrorFunc channel = NULL;
164 xmlParserCtxtPtr pctxt = NULL;
165 void *data = NULL;
166
167 if (ctxt != NULL) {
168 channel = ctxt->error;
169 data = ctxt->userData;
170 pctxt = ctxt->userData;
171 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000172 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000173 XML_ERR_ERROR, NULL, 0,
174 (const char *) str1,
175 (const char *) str3,
176 NULL, int2, 0, msg, str1, int2, str3);
177}
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000178
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000179/**
180 * xmlErrValidWarning:
181 * @ctxt: an XML validation parser context
182 * @node: the node raising the error
183 * @error: the error number
William M. Brackedb65a72004-02-06 07:36:04 +0000184 * @str1: extra information
185 * @str2: extra information
186 * @str3: extra information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000187 *
William M. Brackedb65a72004-02-06 07:36:04 +0000188 * Handle a validation error, provide contextual information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000189 */
190static void
William M. Brackedb65a72004-02-06 07:36:04 +0000191xmlErrValidWarning(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000192 xmlNodePtr node, xmlParserErrors error,
193 const char *msg, const xmlChar * str1,
194 const xmlChar * str2, const xmlChar * str3)
195{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000196 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000197 xmlGenericErrorFunc channel = NULL;
198 xmlParserCtxtPtr pctxt = NULL;
199 void *data = NULL;
200
201 if (ctxt != NULL) {
202 channel = ctxt->error;
203 data = ctxt->userData;
204 pctxt = ctxt->userData;
205 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000206 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000207 XML_ERR_WARNING, NULL, 0,
208 (const char *) str1,
209 (const char *) str1,
210 (const char *) str3, 0, 0, msg, str1, str2, str3);
211}
212
213
Daniel Veillardea7751d2002-12-20 00:16:24 +0000214
215#ifdef LIBXML_REGEXP_ENABLED
216/*
217 * If regexp are enabled we can do continuous validation without the
218 * need of a tree to validate the content model. this is done in each
219 * callbacks.
220 * Each xmlValidState represent the validation state associated to the
221 * set of nodes currently open from the document root to the current element.
222 */
223
224
225typedef struct _xmlValidState {
226 xmlElementPtr elemDecl; /* pointer to the content model */
227 xmlNodePtr node; /* pointer to the current node */
228 xmlRegExecCtxtPtr exec; /* regexp runtime */
229} _xmlValidState;
230
231
232static int
233vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000234 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000235 ctxt->vstateMax = 10;
236 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
237 sizeof(ctxt->vstateTab[0]));
238 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000239 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000240 return(-1);
241 }
242 }
243
244 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000245 xmlValidState *tmp;
246
247 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
248 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
249 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000250 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000251 return(-1);
252 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000253 ctxt->vstateMax *= 2;
254 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000255 }
256 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
257 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
258 ctxt->vstateTab[ctxt->vstateNr].node = node;
259 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
260 if (elemDecl->contModel == NULL)
261 xmlValidBuildContentModel(ctxt, elemDecl);
262 if (elemDecl->contModel != NULL) {
263 ctxt->vstateTab[ctxt->vstateNr].exec =
264 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
265 } else {
266 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000267 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
268 XML_ERR_INTERNAL_ERROR,
269 "Failed to build content model regexp for %s\n",
270 node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000271 }
272 }
273 return(ctxt->vstateNr++);
274}
275
276static int
277vstateVPop(xmlValidCtxtPtr ctxt) {
278 xmlElementPtr elemDecl;
279
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000280 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000281 ctxt->vstateNr--;
282 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
283 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
284 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
285 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
286 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
287 }
288 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
289 if (ctxt->vstateNr >= 1)
290 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
291 else
292 ctxt->vstate = NULL;
293 return(ctxt->vstateNr);
294}
295
296#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000297/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000298 * If regexp are not enabled, it uses a home made algorithm less
299 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000300 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000301 * only restriction is on the deepness of the tree limited by the
302 * size of the occurs bitfield
303 *
304 * this is the content of a saved state for rollbacks
305 */
306
307#define ROLLBACK_OR 0
308#define ROLLBACK_PARENT 1
309
Daniel Veillardb44025c2001-10-11 22:55:55 +0000310typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000311 xmlElementContentPtr cont; /* pointer to the content model subtree */
312 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000313 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000314 unsigned char depth; /* current depth in the overall tree */
315 unsigned char state; /* ROLLBACK_XXX */
316} _xmlValidState;
317
Daniel Veillardfc57b412002-04-29 15:50:14 +0000318#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000319#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
320#define CONT ctxt->vstate->cont
321#define NODE ctxt->vstate->node
322#define DEPTH ctxt->vstate->depth
323#define OCCURS ctxt->vstate->occurs
324#define STATE ctxt->vstate->state
325
Daniel Veillard5344c602001-12-31 16:37:34 +0000326#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
327#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000328
Daniel Veillard5344c602001-12-31 16:37:34 +0000329#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
330#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000331
332static int
333vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
334 xmlNodePtr node, unsigned char depth, long occurs,
335 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000336 int i = ctxt->vstateNr - 1;
337
Daniel Veillard940492d2002-04-15 10:15:25 +0000338 if (ctxt->vstateNr > MAX_RECURSE) {
339 return(-1);
340 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000341 if (ctxt->vstateTab == NULL) {
342 ctxt->vstateMax = 8;
343 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
344 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
345 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000346 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000347 return(-1);
348 }
349 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000350 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000351 xmlValidState *tmp;
352
353 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
354 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
355 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000356 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000357 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000358 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000359 ctxt->vstateMax *= 2;
360 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000361 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000362 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000363 /*
364 * Don't push on the stack a state already here
365 */
366 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
367 (ctxt->vstateTab[i].node == node) &&
368 (ctxt->vstateTab[i].depth == depth) &&
369 (ctxt->vstateTab[i].occurs == occurs) &&
370 (ctxt->vstateTab[i].state == state))
371 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000372 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
373 ctxt->vstateTab[ctxt->vstateNr].node = node;
374 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
375 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
376 ctxt->vstateTab[ctxt->vstateNr].state = state;
377 return(ctxt->vstateNr++);
378}
379
380static int
381vstateVPop(xmlValidCtxtPtr ctxt) {
382 if (ctxt->vstateNr <= 1) return(-1);
383 ctxt->vstateNr--;
384 ctxt->vstate = &ctxt->vstateTab[0];
385 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
386 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
387 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
388 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
389 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
390 return(ctxt->vstateNr);
391}
392
Daniel Veillard118aed72002-09-24 14:13:13 +0000393#endif /* LIBXML_REGEXP_ENABLED */
394
Daniel Veillard1c732d22002-11-30 11:22:59 +0000395static int
396nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
397{
398 if (ctxt->nodeMax <= 0) {
399 ctxt->nodeMax = 4;
400 ctxt->nodeTab =
401 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
402 sizeof(ctxt->nodeTab[0]));
403 if (ctxt->nodeTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000404 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000405 ctxt->nodeMax = 0;
406 return (0);
407 }
408 }
409 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000410 xmlNodePtr *tmp;
411 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
412 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
413 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000414 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000415 return (0);
416 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000417 ctxt->nodeMax *= 2;
418 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000419 }
420 ctxt->nodeTab[ctxt->nodeNr] = value;
421 ctxt->node = value;
422 return (ctxt->nodeNr++);
423}
424static xmlNodePtr
425nodeVPop(xmlValidCtxtPtr ctxt)
426{
427 xmlNodePtr ret;
428
429 if (ctxt->nodeNr <= 0)
430 return (0);
431 ctxt->nodeNr--;
432 if (ctxt->nodeNr > 0)
433 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
434 else
435 ctxt->node = NULL;
436 ret = ctxt->nodeTab[ctxt->nodeNr];
437 ctxt->nodeTab[ctxt->nodeNr] = 0;
438 return (ret);
439}
Owen Taylor3473f882001-02-23 17:55:21 +0000440
Owen Taylor3473f882001-02-23 17:55:21 +0000441#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000442static void
443xmlValidPrintNode(xmlNodePtr cur) {
444 if (cur == NULL) {
445 xmlGenericError(xmlGenericErrorContext, "null");
446 return;
447 }
448 switch (cur->type) {
449 case XML_ELEMENT_NODE:
450 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
451 break;
452 case XML_TEXT_NODE:
453 xmlGenericError(xmlGenericErrorContext, "text ");
454 break;
455 case XML_CDATA_SECTION_NODE:
456 xmlGenericError(xmlGenericErrorContext, "cdata ");
457 break;
458 case XML_ENTITY_REF_NODE:
459 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
460 break;
461 case XML_PI_NODE:
462 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
463 break;
464 case XML_COMMENT_NODE:
465 xmlGenericError(xmlGenericErrorContext, "comment ");
466 break;
467 case XML_ATTRIBUTE_NODE:
468 xmlGenericError(xmlGenericErrorContext, "?attr? ");
469 break;
470 case XML_ENTITY_NODE:
471 xmlGenericError(xmlGenericErrorContext, "?ent? ");
472 break;
473 case XML_DOCUMENT_NODE:
474 xmlGenericError(xmlGenericErrorContext, "?doc? ");
475 break;
476 case XML_DOCUMENT_TYPE_NODE:
477 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
478 break;
479 case XML_DOCUMENT_FRAG_NODE:
480 xmlGenericError(xmlGenericErrorContext, "?frag? ");
481 break;
482 case XML_NOTATION_NODE:
483 xmlGenericError(xmlGenericErrorContext, "?nota? ");
484 break;
485 case XML_HTML_DOCUMENT_NODE:
486 xmlGenericError(xmlGenericErrorContext, "?html? ");
487 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000488#ifdef LIBXML_DOCB_ENABLED
489 case XML_DOCB_DOCUMENT_NODE:
490 xmlGenericError(xmlGenericErrorContext, "?docb? ");
491 break;
492#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000493 case XML_DTD_NODE:
494 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
495 break;
496 case XML_ELEMENT_DECL:
497 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
498 break;
499 case XML_ATTRIBUTE_DECL:
500 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
501 break;
502 case XML_ENTITY_DECL:
503 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
504 break;
505 case XML_NAMESPACE_DECL:
506 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
507 break;
508 case XML_XINCLUDE_START:
509 xmlGenericError(xmlGenericErrorContext, "incstart ");
510 break;
511 case XML_XINCLUDE_END:
512 xmlGenericError(xmlGenericErrorContext, "incend ");
513 break;
514 }
515}
516
517static void
518xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000519 if (cur == NULL)
520 xmlGenericError(xmlGenericErrorContext, "null ");
521 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000522 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000523 cur = cur->next;
524 }
525}
526
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000527static void
528xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000529 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000530
531 expr[0] = 0;
532 xmlGenericError(xmlGenericErrorContext, "valid: ");
533 xmlValidPrintNodeList(cur);
534 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000535 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000536 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
537}
538
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000539static void
540xmlValidDebugState(xmlValidStatePtr state) {
541 xmlGenericError(xmlGenericErrorContext, "(");
542 if (state->cont == NULL)
543 xmlGenericError(xmlGenericErrorContext, "null,");
544 else
545 switch (state->cont->type) {
546 case XML_ELEMENT_CONTENT_PCDATA:
547 xmlGenericError(xmlGenericErrorContext, "pcdata,");
548 break;
549 case XML_ELEMENT_CONTENT_ELEMENT:
550 xmlGenericError(xmlGenericErrorContext, "%s,",
551 state->cont->name);
552 break;
553 case XML_ELEMENT_CONTENT_SEQ:
554 xmlGenericError(xmlGenericErrorContext, "seq,");
555 break;
556 case XML_ELEMENT_CONTENT_OR:
557 xmlGenericError(xmlGenericErrorContext, "or,");
558 break;
559 }
560 xmlValidPrintNode(state->node);
561 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
562 state->depth, state->occurs, state->state);
563}
564
565static void
566xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
567 int i, j;
568
569 xmlGenericError(xmlGenericErrorContext, "state: ");
570 xmlValidDebugState(ctxt->vstate);
571 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
572 ctxt->vstateNr - 1);
573 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
574 xmlValidDebugState(&ctxt->vstateTab[j]);
575 xmlGenericError(xmlGenericErrorContext, "\n");
576}
577
578/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000579#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000580 *****/
581
582#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000583#define DEBUG_VALID_MSG(m) \
584 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
585
Owen Taylor3473f882001-02-23 17:55:21 +0000586#else
587#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000588#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000589#endif
590
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000591/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000592
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000593
Owen Taylor3473f882001-02-23 17:55:21 +0000594#define CHECK_DTD \
595 if (doc == NULL) return(0); \
596 else if ((doc->intSubset == NULL) && \
597 (doc->extSubset == NULL)) return(0)
598
Owen Taylor3473f882001-02-23 17:55:21 +0000599xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
600
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000601#ifdef LIBXML_REGEXP_ENABLED
602
603/************************************************************************
604 * *
605 * Content model validation based on the regexps *
606 * *
607 ************************************************************************/
608
609/**
610 * xmlValidBuildAContentModel:
611 * @content: the content model
612 * @ctxt: the schema parser context
613 * @name: the element name whose content is being built
614 *
615 * Generate the automata sequence needed for that type
616 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000617 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000618 */
619static int
620xmlValidBuildAContentModel(xmlElementContentPtr content,
621 xmlValidCtxtPtr ctxt,
622 const xmlChar *name) {
623 if (content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000624 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
625 "Found NULL content in content model of %s\n",
626 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000627 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000628 }
629 switch (content->type) {
630 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000631 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
632 "Found PCDATA in content model of %s\n",
633 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000634 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000635 break;
636 case XML_ELEMENT_CONTENT_ELEMENT: {
637 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000638 xmlChar fn[50];
639 xmlChar *fullname;
640
641 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
642 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000643 xmlVErrMemory(ctxt, "Building content model");
Daniel Veillardc00cda82003-04-07 10:22:39 +0000644 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000645 }
646
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000647 switch (content->ocur) {
648 case XML_ELEMENT_CONTENT_ONCE:
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 break;
652 case XML_ELEMENT_CONTENT_OPT:
653 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000654 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000655 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
656 break;
657 case XML_ELEMENT_CONTENT_PLUS:
658 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000659 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000660 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000661 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000662 break;
663 case XML_ELEMENT_CONTENT_MULT:
William M. Brack8b0cbb02004-04-17 13:31:06 +0000664 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
665 ctxt->state, NULL);
666 xmlAutomataNewTransition(ctxt->am,
667 ctxt->state, ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000668 break;
669 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000670 if ((fullname != fn) && (fullname != content->name))
671 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000672 break;
673 }
674 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000675 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000676 xmlElementContentOccur ocur;
677
678 /*
679 * Simply iterate over the content
680 */
681 oldstate = ctxt->state;
682 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000683 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
684 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
685 oldstate = ctxt->state;
686 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000687 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000688 xmlValidBuildAContentModel(content->c1, ctxt, name);
689 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000690 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
691 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
692 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000693 oldend = ctxt->state;
694 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000695 switch (ocur) {
696 case XML_ELEMENT_CONTENT_ONCE:
697 break;
698 case XML_ELEMENT_CONTENT_OPT:
699 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
700 break;
701 case XML_ELEMENT_CONTENT_MULT:
702 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000703 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000704 break;
705 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000706 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000707 break;
708 }
709 break;
710 }
711 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000712 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000713 xmlElementContentOccur ocur;
714
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000715 ocur = content->ocur;
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000716 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
717 (ocur == XML_ELEMENT_CONTENT_MULT)) {
718 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
719 ctxt->state, NULL);
720 }
721 oldstate = ctxt->state;
722 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000723
724 /*
725 * iterate over the subtypes and remerge the end with an
726 * epsilon transition
727 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000728 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000729 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000730 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000731 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000732 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000733 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
734 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000735 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000736 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000737 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
738 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000739 switch (ocur) {
740 case XML_ELEMENT_CONTENT_ONCE:
741 break;
742 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000743 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000744 break;
745 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000746 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
747 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000748 break;
749 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000750 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000751 break;
752 }
753 break;
754 }
755 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000756 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
757 "ContentModel broken for element %s\n",
758 (const char *) name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000759 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000760 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000761 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000762}
763/**
764 * xmlValidBuildContentModel:
765 * @ctxt: a validation context
766 * @elem: an element declaration node
767 *
768 * (Re)Build the automata associated to the content model of this
769 * element
770 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000771 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000772 */
773int
774xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000775
776 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000777 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000778 if (elem->type != XML_ELEMENT_DECL)
779 return(0);
780 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
781 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000782 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000783 if (elem->contModel != NULL) {
784 if (!xmlRegexpIsDeterminist(elem->contModel)) {
785 ctxt->valid = 0;
786 return(0);
787 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000788 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000789 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000790
791 ctxt->am = xmlNewAutomata();
792 if (ctxt->am == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000793 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
794 XML_ERR_INTERNAL_ERROR,
795 "Cannot create automata for element %s\n",
796 elem->name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000797 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000798 }
William M. Brack78637da2003-07-31 14:47:38 +0000799 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000800 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
801 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000802 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000803 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000804 char expr[5000];
805 expr[0] = 0;
806 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000807 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
808 XML_DTD_CONTENT_NOT_DETERMINIST,
809 "Content model of %s is not determinist: %s\n",
810 elem->name, BAD_CAST expr, NULL);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000811#ifdef DEBUG_REGEXP_ALGO
812 xmlRegexpPrint(stderr, elem->contModel);
813#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000814 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000815 ctxt->state = NULL;
816 xmlFreeAutomata(ctxt->am);
817 ctxt->am = NULL;
818 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000819 }
820 ctxt->state = NULL;
821 xmlFreeAutomata(ctxt->am);
822 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000823 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000824}
825
826#endif /* LIBXML_REGEXP_ENABLED */
827
Owen Taylor3473f882001-02-23 17:55:21 +0000828/****************************************************************
829 * *
830 * Util functions for data allocation/deallocation *
831 * *
832 ****************************************************************/
833
834/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000835 * xmlNewValidCtxt:
836 *
837 * Allocate a validation context structure.
838 *
839 * Returns NULL if not, otherwise the new validation context structure
840 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000841xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000842 xmlValidCtxtPtr ret;
843
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000844 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000845 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000846 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000847 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000848
849 (void) memset(ret, 0, sizeof (xmlValidCtxt));
850
851 return (ret);
852}
853
854/**
855 * xmlFreeValidCtxt:
856 * @cur: the validation context to free
857 *
858 * Free a validation context structure.
859 */
860void
861xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
862 xmlFree(cur);
863}
864
Daniel Veillard4432df22003-09-28 18:58:27 +0000865#endif /* LIBXML_VALID_ENABLED */
866
Daniel Veillarda37aab82003-06-09 09:10:36 +0000867/**
Owen Taylor3473f882001-02-23 17:55:21 +0000868 * xmlNewElementContent:
869 * @name: the subelement name or NULL
870 * @type: the type of element content decl
871 *
872 * Allocate an element content structure.
873 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000874 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000875 */
876xmlElementContentPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000877xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000878 xmlElementContentPtr ret;
879
880 switch(type) {
881 case XML_ELEMENT_CONTENT_ELEMENT:
882 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000883 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
884 "xmlNewElementContent : name == NULL !\n",
885 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000886 }
887 break;
888 case XML_ELEMENT_CONTENT_PCDATA:
889 case XML_ELEMENT_CONTENT_SEQ:
890 case XML_ELEMENT_CONTENT_OR:
891 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000892 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
893 "xmlNewElementContent : name != NULL !\n",
894 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000895 }
896 break;
897 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000898 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
899 "Internal: ELEMENT content corrupted invalid type\n",
900 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000901 return(NULL);
902 }
903 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
904 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000905 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000906 return(NULL);
907 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000908 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000909 ret->type = type;
910 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000911 if (name != NULL) {
912 xmlChar *prefix = NULL;
913 ret->name = xmlSplitQName2(name, &prefix);
914 if (ret->name == NULL)
915 ret->name = xmlStrdup(name);
916 ret->prefix = prefix;
917 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000918 ret->name = NULL;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000919 ret->prefix = NULL;
920 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000921 ret->c1 = ret->c2 = ret->parent = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000922 return(ret);
923}
924
925/**
926 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000927 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +0000928 *
929 * Build a copy of an element content description.
930 *
931 * Returns the new xmlElementContentPtr or NULL in case of error.
932 */
933xmlElementContentPtr
934xmlCopyElementContent(xmlElementContentPtr cur) {
935 xmlElementContentPtr ret;
936
937 if (cur == NULL) return(NULL);
938 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
939 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000940 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000941 return(NULL);
942 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000943 if (cur->prefix != NULL)
944 ret->prefix = xmlStrdup(cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000945 ret->ocur = cur->ocur;
946 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000947 if (ret->c1 != NULL)
948 ret->c1->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000949 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000950 if (ret->c2 != NULL)
951 ret->c2->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000952 return(ret);
953}
954
955/**
956 * xmlFreeElementContent:
957 * @cur: the element content tree to free
958 *
959 * Free an element content structure. This is a recursive call !
960 */
961void
962xmlFreeElementContent(xmlElementContentPtr cur) {
963 if (cur == NULL) return;
964 switch (cur->type) {
965 case XML_ELEMENT_CONTENT_PCDATA:
966 case XML_ELEMENT_CONTENT_ELEMENT:
967 case XML_ELEMENT_CONTENT_SEQ:
968 case XML_ELEMENT_CONTENT_OR:
969 break;
970 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000971 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
972 "Internal: ELEMENT content corrupted invalid type\n",
973 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000974 return;
975 }
976 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
977 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
978 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000979 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000980 xmlFree(cur);
981}
982
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000983#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000984/**
985 * xmlDumpElementContent:
986 * @buf: An XML buffer
987 * @content: An element table
988 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
989 *
990 * This will dump the content of the element table as an XML DTD definition
991 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000992static void
Owen Taylor3473f882001-02-23 17:55:21 +0000993xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
994 if (content == NULL) return;
995
996 if (glob) xmlBufferWriteChar(buf, "(");
997 switch (content->type) {
998 case XML_ELEMENT_CONTENT_PCDATA:
999 xmlBufferWriteChar(buf, "#PCDATA");
1000 break;
1001 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001002 if (content->prefix != NULL) {
1003 xmlBufferWriteCHAR(buf, content->prefix);
1004 xmlBufferWriteChar(buf, ":");
1005 }
Owen Taylor3473f882001-02-23 17:55:21 +00001006 xmlBufferWriteCHAR(buf, content->name);
1007 break;
1008 case XML_ELEMENT_CONTENT_SEQ:
1009 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1010 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1011 xmlDumpElementContent(buf, content->c1, 1);
1012 else
1013 xmlDumpElementContent(buf, content->c1, 0);
1014 xmlBufferWriteChar(buf, " , ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001015 if ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1016 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
1017 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001018 xmlDumpElementContent(buf, content->c2, 1);
1019 else
1020 xmlDumpElementContent(buf, content->c2, 0);
1021 break;
1022 case XML_ELEMENT_CONTENT_OR:
1023 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1024 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1025 xmlDumpElementContent(buf, content->c1, 1);
1026 else
1027 xmlDumpElementContent(buf, content->c1, 0);
1028 xmlBufferWriteChar(buf, " | ");
William M. Brack4119d1c2004-06-24 02:24:44 +00001029 if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1030 ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
1031 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
Owen Taylor3473f882001-02-23 17:55:21 +00001032 xmlDumpElementContent(buf, content->c2, 1);
1033 else
1034 xmlDumpElementContent(buf, content->c2, 0);
1035 break;
1036 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001037 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1038 "Internal: ELEMENT content corrupted invalid type\n",
1039 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001040 }
1041 if (glob)
1042 xmlBufferWriteChar(buf, ")");
1043 switch (content->ocur) {
1044 case XML_ELEMENT_CONTENT_ONCE:
1045 break;
1046 case XML_ELEMENT_CONTENT_OPT:
1047 xmlBufferWriteChar(buf, "?");
1048 break;
1049 case XML_ELEMENT_CONTENT_MULT:
1050 xmlBufferWriteChar(buf, "*");
1051 break;
1052 case XML_ELEMENT_CONTENT_PLUS:
1053 xmlBufferWriteChar(buf, "+");
1054 break;
1055 }
1056}
1057
1058/**
1059 * xmlSprintfElementContent:
1060 * @buf: an output buffer
1061 * @content: An element table
1062 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1063 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001064 * Deprecated, unsafe, use xmlSnprintfElementContent
1065 */
1066void
1067xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1068 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1069 int glob ATTRIBUTE_UNUSED) {
1070}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001071#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001072
1073/**
1074 * xmlSnprintfElementContent:
1075 * @buf: an output buffer
1076 * @size: the buffer size
1077 * @content: An element table
1078 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1079 *
Owen Taylor3473f882001-02-23 17:55:21 +00001080 * This will dump the content of the element content definition
1081 * Intended just for the debug routine
1082 */
1083void
Daniel Veillardd3d06722001-08-15 12:06:36 +00001084xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int glob) {
1085 int len;
1086
Owen Taylor3473f882001-02-23 17:55:21 +00001087 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001088 len = strlen(buf);
1089 if (size - len < 50) {
1090 if ((size - len > 4) && (buf[len - 1] != '.'))
1091 strcat(buf, " ...");
1092 return;
1093 }
Owen Taylor3473f882001-02-23 17:55:21 +00001094 if (glob) strcat(buf, "(");
1095 switch (content->type) {
1096 case XML_ELEMENT_CONTENT_PCDATA:
1097 strcat(buf, "#PCDATA");
1098 break;
1099 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001100 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001101 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001102 strcat(buf, " ...");
1103 return;
1104 }
1105 strcat(buf, (char *) content->prefix);
1106 strcat(buf, ":");
1107 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001108 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001109 strcat(buf, " ...");
1110 return;
1111 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001112 if (content->name != NULL)
1113 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001114 break;
1115 case XML_ELEMENT_CONTENT_SEQ:
1116 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1117 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001118 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001119 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001120 xmlSnprintfElementContent(buf, size, content->c1, 0);
1121 len = strlen(buf);
1122 if (size - len < 50) {
1123 if ((size - len > 4) && (buf[len - 1] != '.'))
1124 strcat(buf, " ...");
1125 return;
1126 }
Owen Taylor3473f882001-02-23 17:55:21 +00001127 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001128 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1129 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1130 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001131 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001132 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001133 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001134 break;
1135 case XML_ELEMENT_CONTENT_OR:
1136 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1137 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001138 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001139 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001140 xmlSnprintfElementContent(buf, size, content->c1, 0);
1141 len = strlen(buf);
1142 if (size - len < 50) {
1143 if ((size - len > 4) && (buf[len - 1] != '.'))
1144 strcat(buf, " ...");
1145 return;
1146 }
Owen Taylor3473f882001-02-23 17:55:21 +00001147 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001148 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1149 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1150 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001151 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001152 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001153 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001154 break;
1155 }
1156 if (glob)
1157 strcat(buf, ")");
1158 switch (content->ocur) {
1159 case XML_ELEMENT_CONTENT_ONCE:
1160 break;
1161 case XML_ELEMENT_CONTENT_OPT:
1162 strcat(buf, "?");
1163 break;
1164 case XML_ELEMENT_CONTENT_MULT:
1165 strcat(buf, "*");
1166 break;
1167 case XML_ELEMENT_CONTENT_PLUS:
1168 strcat(buf, "+");
1169 break;
1170 }
1171}
1172
1173/****************************************************************
1174 * *
1175 * Registration of DTD declarations *
1176 * *
1177 ****************************************************************/
1178
1179/**
1180 * xmlCreateElementTable:
1181 *
1182 * create and initialize an empty element hash table.
1183 *
1184 * Returns the xmlElementTablePtr just created or NULL in case of error.
1185 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001186static xmlElementTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001187xmlCreateElementTable(void) {
1188 return(xmlHashCreate(0));
1189}
1190
1191/**
1192 * xmlFreeElement:
1193 * @elem: An element
1194 *
1195 * Deallocate the memory used by an element definition
1196 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001197static void
Owen Taylor3473f882001-02-23 17:55:21 +00001198xmlFreeElement(xmlElementPtr elem) {
1199 if (elem == NULL) return;
1200 xmlUnlinkNode((xmlNodePtr) elem);
1201 xmlFreeElementContent(elem->content);
1202 if (elem->name != NULL)
1203 xmlFree((xmlChar *) elem->name);
1204 if (elem->prefix != NULL)
1205 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001206#ifdef LIBXML_REGEXP_ENABLED
1207 if (elem->contModel != NULL)
1208 xmlRegFreeRegexp(elem->contModel);
1209#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001210 xmlFree(elem);
1211}
1212
1213
1214/**
1215 * xmlAddElementDecl:
1216 * @ctxt: the validation context
1217 * @dtd: pointer to the DTD
1218 * @name: the entity name
1219 * @type: the element type
1220 * @content: the element content tree or NULL
1221 *
1222 * Register a new element declaration
1223 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001224 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001225 */
1226xmlElementPtr
William M. Brackedb65a72004-02-06 07:36:04 +00001227xmlAddElementDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001228 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001229 xmlElementTypeVal type,
1230 xmlElementContentPtr content) {
1231 xmlElementPtr ret;
1232 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001233 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001234 xmlChar *ns, *uqname;
1235
1236 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001237 return(NULL);
1238 }
1239 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001240 return(NULL);
1241 }
1242 switch (type) {
1243 case XML_ELEMENT_TYPE_EMPTY:
1244 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001245 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1246 "xmlAddElementDecl: content != NULL for EMPTY\n",
1247 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001248 return(NULL);
1249 }
1250 break;
1251 case XML_ELEMENT_TYPE_ANY:
1252 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001253 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1254 "xmlAddElementDecl: content != NULL for ANY\n",
1255 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001256 return(NULL);
1257 }
1258 break;
1259 case XML_ELEMENT_TYPE_MIXED:
1260 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001261 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1262 "xmlAddElementDecl: content == NULL for MIXED\n",
1263 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001264 return(NULL);
1265 }
1266 break;
1267 case XML_ELEMENT_TYPE_ELEMENT:
1268 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001269 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1270 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1271 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001272 return(NULL);
1273 }
1274 break;
1275 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001276 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1277 "Internal: ELEMENT decl corrupted invalid type\n",
1278 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001279 return(NULL);
1280 }
1281
1282 /*
1283 * check if name is a QName
1284 */
1285 uqname = xmlSplitQName2(name, &ns);
1286 if (uqname != NULL)
1287 name = uqname;
1288
1289 /*
1290 * Create the Element table if needed.
1291 */
1292 table = (xmlElementTablePtr) dtd->elements;
1293 if (table == NULL) {
1294 table = xmlCreateElementTable();
1295 dtd->elements = (void *) table;
1296 }
1297 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001298 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001299 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001300 if (uqname != NULL)
1301 xmlFree(uqname);
1302 if (ns != NULL)
1303 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001304 return(NULL);
1305 }
1306
Daniel Veillarda10efa82001-04-18 13:09:01 +00001307 /*
1308 * lookup old attributes inserted on an undefined element in the
1309 * internal subset.
1310 */
1311 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1312 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1313 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1314 oldAttributes = ret->attributes;
1315 ret->attributes = NULL;
1316 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1317 xmlFreeElement(ret);
1318 }
Owen Taylor3473f882001-02-23 17:55:21 +00001319 }
Owen Taylor3473f882001-02-23 17:55:21 +00001320
1321 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001322 * The element may already be present if one of its attribute
1323 * was registered first
1324 */
1325 ret = xmlHashLookup2(table, name, ns);
1326 if (ret != NULL) {
1327 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001328#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001329 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001330 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001331 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001332 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1333 "Redefinition of element %s\n",
1334 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001335#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001336 if (uqname != NULL)
1337 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001338 if (ns != NULL)
1339 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001340 return(NULL);
1341 }
1342 } else {
1343 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1344 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001345 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001346 if (uqname != NULL)
1347 xmlFree(uqname);
1348 if (ns != NULL)
1349 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001350 return(NULL);
1351 }
1352 memset(ret, 0, sizeof(xmlElement));
1353 ret->type = XML_ELEMENT_DECL;
1354
1355 /*
1356 * fill the structure.
1357 */
1358 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001359 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001360 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001361 if (uqname != NULL)
1362 xmlFree(uqname);
1363 if (ns != NULL)
1364 xmlFree(ns);
1365 xmlFree(ret);
1366 return(NULL);
1367 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001368 ret->prefix = ns;
1369
1370 /*
1371 * Validity Check:
1372 * Insertion must not fail
1373 */
1374 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001375#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001376 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001377 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001378 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001379 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1380 "Redefinition of element %s\n",
1381 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001382#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001383 xmlFreeElement(ret);
1384 if (uqname != NULL)
1385 xmlFree(uqname);
1386 return(NULL);
1387 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001388 /*
1389 * For new element, may have attributes from earlier
1390 * definition in internal subset
1391 */
1392 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001393 }
1394
1395 /*
1396 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001397 */
1398 ret->etype = type;
Owen Taylor3473f882001-02-23 17:55:21 +00001399 ret->content = xmlCopyElementContent(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001400
1401 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001402 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001403 */
1404 ret->parent = dtd;
1405 ret->doc = dtd->doc;
1406 if (dtd->last == NULL) {
1407 dtd->children = dtd->last = (xmlNodePtr) ret;
1408 } else {
1409 dtd->last->next = (xmlNodePtr) ret;
1410 ret->prev = dtd->last;
1411 dtd->last = (xmlNodePtr) ret;
1412 }
1413 if (uqname != NULL)
1414 xmlFree(uqname);
1415 return(ret);
1416}
1417
1418/**
1419 * xmlFreeElementTable:
1420 * @table: An element table
1421 *
1422 * Deallocate the memory used by an element hash table.
1423 */
1424void
1425xmlFreeElementTable(xmlElementTablePtr table) {
1426 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1427}
1428
Daniel Veillard652327a2003-09-29 18:02:38 +00001429#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001430/**
1431 * xmlCopyElement:
1432 * @elem: An element
1433 *
1434 * Build a copy of an element.
1435 *
1436 * Returns the new xmlElementPtr or NULL in case of error.
1437 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001438static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001439xmlCopyElement(xmlElementPtr elem) {
1440 xmlElementPtr cur;
1441
1442 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1443 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001444 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001445 return(NULL);
1446 }
1447 memset(cur, 0, sizeof(xmlElement));
1448 cur->type = XML_ELEMENT_DECL;
1449 cur->etype = elem->etype;
1450 if (elem->name != NULL)
1451 cur->name = xmlStrdup(elem->name);
1452 else
1453 cur->name = NULL;
1454 if (elem->prefix != NULL)
1455 cur->prefix = xmlStrdup(elem->prefix);
1456 else
1457 cur->prefix = NULL;
1458 cur->content = xmlCopyElementContent(elem->content);
1459 /* TODO : rebuild the attribute list on the copy */
1460 cur->attributes = NULL;
1461 return(cur);
1462}
1463
1464/**
1465 * xmlCopyElementTable:
1466 * @table: An element table
1467 *
1468 * Build a copy of an element table.
1469 *
1470 * Returns the new xmlElementTablePtr or NULL in case of error.
1471 */
1472xmlElementTablePtr
1473xmlCopyElementTable(xmlElementTablePtr table) {
1474 return((xmlElementTablePtr) xmlHashCopy(table,
1475 (xmlHashCopier) xmlCopyElement));
1476}
Daniel Veillard652327a2003-09-29 18:02:38 +00001477#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001478
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001479#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001480/**
1481 * xmlDumpElementDecl:
1482 * @buf: the XML buffer output
1483 * @elem: An element table
1484 *
1485 * This will dump the content of the element declaration as an XML
1486 * DTD definition
1487 */
1488void
1489xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1490 switch (elem->etype) {
1491 case XML_ELEMENT_TYPE_EMPTY:
1492 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001493 if (elem->prefix != NULL) {
1494 xmlBufferWriteCHAR(buf, elem->prefix);
1495 xmlBufferWriteChar(buf, ":");
1496 }
Owen Taylor3473f882001-02-23 17:55:21 +00001497 xmlBufferWriteCHAR(buf, elem->name);
1498 xmlBufferWriteChar(buf, " EMPTY>\n");
1499 break;
1500 case XML_ELEMENT_TYPE_ANY:
1501 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001502 if (elem->prefix != NULL) {
1503 xmlBufferWriteCHAR(buf, elem->prefix);
1504 xmlBufferWriteChar(buf, ":");
1505 }
Owen Taylor3473f882001-02-23 17:55:21 +00001506 xmlBufferWriteCHAR(buf, elem->name);
1507 xmlBufferWriteChar(buf, " ANY>\n");
1508 break;
1509 case XML_ELEMENT_TYPE_MIXED:
1510 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001511 if (elem->prefix != NULL) {
1512 xmlBufferWriteCHAR(buf, elem->prefix);
1513 xmlBufferWriteChar(buf, ":");
1514 }
Owen Taylor3473f882001-02-23 17:55:21 +00001515 xmlBufferWriteCHAR(buf, elem->name);
1516 xmlBufferWriteChar(buf, " ");
1517 xmlDumpElementContent(buf, elem->content, 1);
1518 xmlBufferWriteChar(buf, ">\n");
1519 break;
1520 case XML_ELEMENT_TYPE_ELEMENT:
1521 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001522 if (elem->prefix != NULL) {
1523 xmlBufferWriteCHAR(buf, elem->prefix);
1524 xmlBufferWriteChar(buf, ":");
1525 }
Owen Taylor3473f882001-02-23 17:55:21 +00001526 xmlBufferWriteCHAR(buf, elem->name);
1527 xmlBufferWriteChar(buf, " ");
1528 xmlDumpElementContent(buf, elem->content, 1);
1529 xmlBufferWriteChar(buf, ">\n");
1530 break;
1531 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001532 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1533 "Internal: ELEMENT struct corrupted invalid type\n",
1534 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001535 }
1536}
1537
1538/**
William M. Brack9e660592003-10-20 14:56:06 +00001539 * xmlDumpElementDeclScan:
1540 * @elem: An element table
1541 * @buf: the XML buffer output
1542 *
1543 * This routine is used by the hash scan function. It just reverses
1544 * the arguments.
1545 */
1546static void
1547xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1548 xmlDumpElementDecl(buf, elem);
1549}
1550
1551/**
Owen Taylor3473f882001-02-23 17:55:21 +00001552 * xmlDumpElementTable:
1553 * @buf: the XML buffer output
1554 * @table: An element table
1555 *
1556 * This will dump the content of the element table as an XML DTD definition
1557 */
1558void
1559xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00001560 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001561}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001562#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001563
1564/**
1565 * xmlCreateEnumeration:
1566 * @name: the enumeration name or NULL
1567 *
1568 * create and initialize an enumeration attribute node.
1569 *
1570 * Returns the xmlEnumerationPtr just created or NULL in case
1571 * of error.
1572 */
1573xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001574xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001575 xmlEnumerationPtr ret;
1576
1577 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1578 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001579 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001580 return(NULL);
1581 }
1582 memset(ret, 0, sizeof(xmlEnumeration));
1583
1584 if (name != NULL)
1585 ret->name = xmlStrdup(name);
1586 return(ret);
1587}
1588
1589/**
1590 * xmlFreeEnumeration:
1591 * @cur: the tree to free.
1592 *
1593 * free an enumeration attribute node (recursive).
1594 */
1595void
1596xmlFreeEnumeration(xmlEnumerationPtr cur) {
1597 if (cur == NULL) return;
1598
1599 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1600
1601 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001602 xmlFree(cur);
1603}
1604
Daniel Veillard652327a2003-09-29 18:02:38 +00001605#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001606/**
1607 * xmlCopyEnumeration:
1608 * @cur: the tree to copy.
1609 *
1610 * Copy an enumeration attribute node (recursive).
1611 *
1612 * Returns the xmlEnumerationPtr just created or NULL in case
1613 * of error.
1614 */
1615xmlEnumerationPtr
1616xmlCopyEnumeration(xmlEnumerationPtr cur) {
1617 xmlEnumerationPtr ret;
1618
1619 if (cur == NULL) return(NULL);
1620 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1621
1622 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1623 else ret->next = NULL;
1624
1625 return(ret);
1626}
Daniel Veillard652327a2003-09-29 18:02:38 +00001627#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001628
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001629#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001630/**
1631 * xmlDumpEnumeration:
1632 * @buf: the XML buffer output
1633 * @enum: An enumeration
1634 *
1635 * This will dump the content of the enumeration
1636 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001637static void
Owen Taylor3473f882001-02-23 17:55:21 +00001638xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1639 if (cur == NULL) return;
1640
1641 xmlBufferWriteCHAR(buf, cur->name);
1642 if (cur->next == NULL)
1643 xmlBufferWriteChar(buf, ")");
1644 else {
1645 xmlBufferWriteChar(buf, " | ");
1646 xmlDumpEnumeration(buf, cur->next);
1647 }
1648}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001649#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001650
1651/**
1652 * xmlCreateAttributeTable:
1653 *
1654 * create and initialize an empty attribute hash table.
1655 *
1656 * Returns the xmlAttributeTablePtr just created or NULL in case
1657 * of error.
1658 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001659static xmlAttributeTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001660xmlCreateAttributeTable(void) {
1661 return(xmlHashCreate(0));
1662}
1663
Daniel Veillard4432df22003-09-28 18:58:27 +00001664#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001665/**
1666 * xmlScanAttributeDeclCallback:
1667 * @attr: the attribute decl
1668 * @list: the list to update
1669 *
1670 * Callback called by xmlScanAttributeDecl when a new attribute
1671 * has to be entered in the list.
1672 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001673static void
Owen Taylor3473f882001-02-23 17:55:21 +00001674xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001675 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001676 attr->nexth = *list;
1677 *list = attr;
1678}
1679
1680/**
1681 * xmlScanAttributeDecl:
1682 * @dtd: pointer to the DTD
1683 * @elem: the element name
1684 *
1685 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001686 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001687 *
1688 * Returns the pointer to the first attribute decl in the chain,
1689 * possibly NULL.
1690 */
1691xmlAttributePtr
1692xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1693 xmlAttributePtr ret = NULL;
1694 xmlAttributeTablePtr table;
1695
1696 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001697 return(NULL);
1698 }
1699 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001700 return(NULL);
1701 }
1702 table = (xmlAttributeTablePtr) dtd->attributes;
1703 if (table == NULL)
1704 return(NULL);
1705
1706 /* WRONG !!! */
1707 xmlHashScan3(table, NULL, NULL, elem,
1708 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1709 return(ret);
1710}
1711
1712/**
1713 * xmlScanIDAttributeDecl:
1714 * @ctxt: the validation context
1715 * @elem: the element name
1716 *
1717 * Verify that the element don't have too many ID attributes
1718 * declared.
1719 *
1720 * Returns the number of ID attributes found.
1721 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001722static int
Owen Taylor3473f882001-02-23 17:55:21 +00001723xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1724 xmlAttributePtr cur;
1725 int ret = 0;
1726
1727 if (elem == NULL) return(0);
1728 cur = elem->attributes;
1729 while (cur != NULL) {
1730 if (cur->atype == XML_ATTRIBUTE_ID) {
1731 ret ++;
1732 if (ret > 1)
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001733 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001734 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001735 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001736 }
1737 cur = cur->nexth;
1738 }
1739 return(ret);
1740}
Daniel Veillard4432df22003-09-28 18:58:27 +00001741#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001742
1743/**
1744 * xmlFreeAttribute:
1745 * @elem: An attribute
1746 *
1747 * Deallocate the memory used by an attribute definition
1748 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001749static void
Owen Taylor3473f882001-02-23 17:55:21 +00001750xmlFreeAttribute(xmlAttributePtr attr) {
1751 if (attr == NULL) return;
1752 xmlUnlinkNode((xmlNodePtr) attr);
1753 if (attr->tree != NULL)
1754 xmlFreeEnumeration(attr->tree);
1755 if (attr->elem != NULL)
1756 xmlFree((xmlChar *) attr->elem);
1757 if (attr->name != NULL)
1758 xmlFree((xmlChar *) attr->name);
1759 if (attr->defaultValue != NULL)
1760 xmlFree((xmlChar *) attr->defaultValue);
1761 if (attr->prefix != NULL)
1762 xmlFree((xmlChar *) attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001763 xmlFree(attr);
1764}
1765
1766
1767/**
1768 * xmlAddAttributeDecl:
1769 * @ctxt: the validation context
1770 * @dtd: pointer to the DTD
1771 * @elem: the element name
1772 * @name: the attribute name
1773 * @ns: the attribute namespace prefix
1774 * @type: the attribute type
1775 * @def: the attribute default type
1776 * @defaultValue: the attribute default value
1777 * @tree: if it's an enumeration, the associated list
1778 *
1779 * Register a new attribute declaration
1780 * Note that @tree becomes the ownership of the DTD
1781 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001782 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001783 */
1784xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001785xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001786 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001787 const xmlChar *name, const xmlChar *ns,
1788 xmlAttributeType type, xmlAttributeDefault def,
1789 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1790 xmlAttributePtr ret;
1791 xmlAttributeTablePtr table;
1792 xmlElementPtr elemDef;
1793
1794 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001795 xmlFreeEnumeration(tree);
1796 return(NULL);
1797 }
1798 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001799 xmlFreeEnumeration(tree);
1800 return(NULL);
1801 }
1802 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001803 xmlFreeEnumeration(tree);
1804 return(NULL);
1805 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001806
Daniel Veillard4432df22003-09-28 18:58:27 +00001807#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001808 /*
1809 * Check the type and possibly the default value.
1810 */
1811 switch (type) {
1812 case XML_ATTRIBUTE_CDATA:
1813 break;
1814 case XML_ATTRIBUTE_ID:
1815 break;
1816 case XML_ATTRIBUTE_IDREF:
1817 break;
1818 case XML_ATTRIBUTE_IDREFS:
1819 break;
1820 case XML_ATTRIBUTE_ENTITY:
1821 break;
1822 case XML_ATTRIBUTE_ENTITIES:
1823 break;
1824 case XML_ATTRIBUTE_NMTOKEN:
1825 break;
1826 case XML_ATTRIBUTE_NMTOKENS:
1827 break;
1828 case XML_ATTRIBUTE_ENUMERATION:
1829 break;
1830 case XML_ATTRIBUTE_NOTATION:
1831 break;
1832 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001833 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1834 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1835 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001836 xmlFreeEnumeration(tree);
1837 return(NULL);
1838 }
1839 if ((defaultValue != NULL) &&
1840 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001841 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1842 "Attribute %s of %s: invalid default value\n",
1843 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00001844 defaultValue = NULL;
Daniel Veillardd01fd3e2002-02-18 22:27:47 +00001845 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001846 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001847#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001848
1849 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001850 * Check first that an attribute defined in the external subset wasn't
1851 * already defined in the internal subset
1852 */
1853 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1854 (dtd->doc->intSubset != NULL) &&
1855 (dtd->doc->intSubset->attributes != NULL)) {
1856 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1857 if (ret != NULL)
1858 return(NULL);
1859 }
1860
1861 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001862 * Create the Attribute table if needed.
1863 */
1864 table = (xmlAttributeTablePtr) dtd->attributes;
1865 if (table == NULL) {
1866 table = xmlCreateAttributeTable();
1867 dtd->attributes = (void *) table;
1868 }
1869 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001870 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001871 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001872 return(NULL);
1873 }
1874
1875
1876 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1877 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001878 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001879 return(NULL);
1880 }
1881 memset(ret, 0, sizeof(xmlAttribute));
1882 ret->type = XML_ATTRIBUTE_DECL;
1883
1884 /*
1885 * fill the structure.
1886 */
1887 ret->atype = type;
1888 ret->name = xmlStrdup(name);
1889 ret->prefix = xmlStrdup(ns);
1890 ret->elem = xmlStrdup(elem);
1891 ret->def = def;
1892 ret->tree = tree;
1893 if (defaultValue != NULL)
1894 ret->defaultValue = xmlStrdup(defaultValue);
1895
1896 /*
1897 * Validity Check:
1898 * Search the DTD for previous declarations of the ATTLIST
1899 */
1900 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001901#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001902 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001903 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00001904 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001905 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00001906 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001907 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001908#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001909 xmlFreeAttribute(ret);
1910 return(NULL);
1911 }
1912
1913 /*
1914 * Validity Check:
1915 * Multiple ID per element
1916 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001917 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001918 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00001919
Daniel Veillard4432df22003-09-28 18:58:27 +00001920#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001921 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00001922 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001923 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00001924 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001925 elem, name, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00001926 ctxt->valid = 0;
1927 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001928#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00001929
Daniel Veillard48da9102001-08-07 01:10:10 +00001930 /*
1931 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001932 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00001933 */
1934 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1935 ((ret->prefix != NULL &&
1936 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1937 ret->nexth = elemDef->attributes;
1938 elemDef->attributes = ret;
1939 } else {
1940 xmlAttributePtr tmp = elemDef->attributes;
1941
1942 while ((tmp != NULL) &&
1943 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1944 ((ret->prefix != NULL &&
1945 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1946 if (tmp->nexth == NULL)
1947 break;
1948 tmp = tmp->nexth;
1949 }
1950 if (tmp != NULL) {
1951 ret->nexth = tmp->nexth;
1952 tmp->nexth = ret;
1953 } else {
1954 ret->nexth = elemDef->attributes;
1955 elemDef->attributes = ret;
1956 }
1957 }
Owen Taylor3473f882001-02-23 17:55:21 +00001958 }
1959
1960 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001961 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001962 */
1963 ret->parent = dtd;
1964 ret->doc = dtd->doc;
1965 if (dtd->last == NULL) {
1966 dtd->children = dtd->last = (xmlNodePtr) ret;
1967 } else {
1968 dtd->last->next = (xmlNodePtr) ret;
1969 ret->prev = dtd->last;
1970 dtd->last = (xmlNodePtr) ret;
1971 }
1972 return(ret);
1973}
1974
1975/**
1976 * xmlFreeAttributeTable:
1977 * @table: An attribute table
1978 *
1979 * Deallocate the memory used by an entities hash table.
1980 */
1981void
1982xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1983 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
1984}
1985
Daniel Veillard652327a2003-09-29 18:02:38 +00001986#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001987/**
1988 * xmlCopyAttribute:
1989 * @attr: An attribute
1990 *
1991 * Build a copy of an attribute.
1992 *
1993 * Returns the new xmlAttributePtr or NULL in case of error.
1994 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001995static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001996xmlCopyAttribute(xmlAttributePtr attr) {
1997 xmlAttributePtr cur;
1998
1999 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2000 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002001 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002002 return(NULL);
2003 }
2004 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00002005 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00002006 cur->atype = attr->atype;
2007 cur->def = attr->def;
2008 cur->tree = xmlCopyEnumeration(attr->tree);
2009 if (attr->elem != NULL)
2010 cur->elem = xmlStrdup(attr->elem);
2011 if (attr->name != NULL)
2012 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002013 if (attr->prefix != NULL)
2014 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002015 if (attr->defaultValue != NULL)
2016 cur->defaultValue = xmlStrdup(attr->defaultValue);
2017 return(cur);
2018}
2019
2020/**
2021 * xmlCopyAttributeTable:
2022 * @table: An attribute table
2023 *
2024 * Build a copy of an attribute table.
2025 *
2026 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2027 */
2028xmlAttributeTablePtr
2029xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2030 return((xmlAttributeTablePtr) xmlHashCopy(table,
2031 (xmlHashCopier) xmlCopyAttribute));
2032}
Daniel Veillard652327a2003-09-29 18:02:38 +00002033#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002034
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002035#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002036/**
2037 * xmlDumpAttributeDecl:
2038 * @buf: the XML buffer output
2039 * @attr: An attribute declaration
2040 *
2041 * This will dump the content of the attribute declaration as an XML
2042 * DTD definition
2043 */
2044void
2045xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2046 xmlBufferWriteChar(buf, "<!ATTLIST ");
2047 xmlBufferWriteCHAR(buf, attr->elem);
2048 xmlBufferWriteChar(buf, " ");
2049 if (attr->prefix != NULL) {
2050 xmlBufferWriteCHAR(buf, attr->prefix);
2051 xmlBufferWriteChar(buf, ":");
2052 }
2053 xmlBufferWriteCHAR(buf, attr->name);
2054 switch (attr->atype) {
2055 case XML_ATTRIBUTE_CDATA:
2056 xmlBufferWriteChar(buf, " CDATA");
2057 break;
2058 case XML_ATTRIBUTE_ID:
2059 xmlBufferWriteChar(buf, " ID");
2060 break;
2061 case XML_ATTRIBUTE_IDREF:
2062 xmlBufferWriteChar(buf, " IDREF");
2063 break;
2064 case XML_ATTRIBUTE_IDREFS:
2065 xmlBufferWriteChar(buf, " IDREFS");
2066 break;
2067 case XML_ATTRIBUTE_ENTITY:
2068 xmlBufferWriteChar(buf, " ENTITY");
2069 break;
2070 case XML_ATTRIBUTE_ENTITIES:
2071 xmlBufferWriteChar(buf, " ENTITIES");
2072 break;
2073 case XML_ATTRIBUTE_NMTOKEN:
2074 xmlBufferWriteChar(buf, " NMTOKEN");
2075 break;
2076 case XML_ATTRIBUTE_NMTOKENS:
2077 xmlBufferWriteChar(buf, " NMTOKENS");
2078 break;
2079 case XML_ATTRIBUTE_ENUMERATION:
2080 xmlBufferWriteChar(buf, " (");
2081 xmlDumpEnumeration(buf, attr->tree);
2082 break;
2083 case XML_ATTRIBUTE_NOTATION:
2084 xmlBufferWriteChar(buf, " NOTATION (");
2085 xmlDumpEnumeration(buf, attr->tree);
2086 break;
2087 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002088 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2089 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2090 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002091 }
2092 switch (attr->def) {
2093 case XML_ATTRIBUTE_NONE:
2094 break;
2095 case XML_ATTRIBUTE_REQUIRED:
2096 xmlBufferWriteChar(buf, " #REQUIRED");
2097 break;
2098 case XML_ATTRIBUTE_IMPLIED:
2099 xmlBufferWriteChar(buf, " #IMPLIED");
2100 break;
2101 case XML_ATTRIBUTE_FIXED:
2102 xmlBufferWriteChar(buf, " #FIXED");
2103 break;
2104 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002105 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2106 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2107 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002108 }
2109 if (attr->defaultValue != NULL) {
2110 xmlBufferWriteChar(buf, " ");
2111 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2112 }
2113 xmlBufferWriteChar(buf, ">\n");
2114}
2115
2116/**
William M. Brack9e660592003-10-20 14:56:06 +00002117 * xmlDumpAttributeDeclScan:
2118 * @attr: An attribute declaration
2119 * @buf: the XML buffer output
2120 *
2121 * This is used with the hash scan function - just reverses arguments
2122 */
2123static void
2124xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2125 xmlDumpAttributeDecl(buf, attr);
2126}
2127
2128/**
Owen Taylor3473f882001-02-23 17:55:21 +00002129 * xmlDumpAttributeTable:
2130 * @buf: the XML buffer output
2131 * @table: An attribute table
2132 *
2133 * This will dump the content of the attribute table as an XML DTD definition
2134 */
2135void
2136xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002137 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002138}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002139#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002140
2141/************************************************************************
2142 * *
2143 * NOTATIONs *
2144 * *
2145 ************************************************************************/
2146/**
2147 * xmlCreateNotationTable:
2148 *
2149 * create and initialize an empty notation hash table.
2150 *
2151 * Returns the xmlNotationTablePtr just created or NULL in case
2152 * of error.
2153 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002154static xmlNotationTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002155xmlCreateNotationTable(void) {
2156 return(xmlHashCreate(0));
2157}
2158
2159/**
2160 * xmlFreeNotation:
2161 * @not: A notation
2162 *
2163 * Deallocate the memory used by an notation definition
2164 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002165static void
Owen Taylor3473f882001-02-23 17:55:21 +00002166xmlFreeNotation(xmlNotationPtr nota) {
2167 if (nota == NULL) return;
2168 if (nota->name != NULL)
2169 xmlFree((xmlChar *) nota->name);
2170 if (nota->PublicID != NULL)
2171 xmlFree((xmlChar *) nota->PublicID);
2172 if (nota->SystemID != NULL)
2173 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002174 xmlFree(nota);
2175}
2176
2177
2178/**
2179 * xmlAddNotationDecl:
2180 * @dtd: pointer to the DTD
2181 * @ctxt: the validation context
2182 * @name: the entity name
2183 * @PublicID: the public identifier or NULL
2184 * @SystemID: the system identifier or NULL
2185 *
2186 * Register a new notation declaration
2187 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002188 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002189 */
2190xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002191xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002192 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002193 const xmlChar *PublicID, const xmlChar *SystemID) {
2194 xmlNotationPtr ret;
2195 xmlNotationTablePtr table;
2196
2197 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002198 return(NULL);
2199 }
2200 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002201 return(NULL);
2202 }
2203 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002204 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002205 }
2206
2207 /*
2208 * Create the Notation table if needed.
2209 */
2210 table = (xmlNotationTablePtr) dtd->notations;
2211 if (table == NULL)
2212 dtd->notations = table = xmlCreateNotationTable();
2213 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002214 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002215 "xmlAddNotationDecl: Table creation failed!\n");
2216 return(NULL);
2217 }
2218
2219 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2220 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002221 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002222 return(NULL);
2223 }
2224 memset(ret, 0, sizeof(xmlNotation));
2225
2226 /*
2227 * fill the structure.
2228 */
2229 ret->name = xmlStrdup(name);
2230 if (SystemID != NULL)
2231 ret->SystemID = xmlStrdup(SystemID);
2232 if (PublicID != NULL)
2233 ret->PublicID = xmlStrdup(PublicID);
2234
2235 /*
2236 * Validity Check:
2237 * Check the DTD for previous declarations of the ATTLIST
2238 */
2239 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002240#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002241 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2242 "xmlAddNotationDecl: %s already defined\n",
2243 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002244#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002245 xmlFreeNotation(ret);
2246 return(NULL);
2247 }
2248 return(ret);
2249}
2250
2251/**
2252 * xmlFreeNotationTable:
2253 * @table: An notation table
2254 *
2255 * Deallocate the memory used by an entities hash table.
2256 */
2257void
2258xmlFreeNotationTable(xmlNotationTablePtr table) {
2259 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2260}
2261
Daniel Veillard652327a2003-09-29 18:02:38 +00002262#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002263/**
2264 * xmlCopyNotation:
2265 * @nota: A notation
2266 *
2267 * Build a copy of a notation.
2268 *
2269 * Returns the new xmlNotationPtr or NULL in case of error.
2270 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002271static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002272xmlCopyNotation(xmlNotationPtr nota) {
2273 xmlNotationPtr cur;
2274
2275 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2276 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002277 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002278 return(NULL);
2279 }
2280 if (nota->name != NULL)
2281 cur->name = xmlStrdup(nota->name);
2282 else
2283 cur->name = NULL;
2284 if (nota->PublicID != NULL)
2285 cur->PublicID = xmlStrdup(nota->PublicID);
2286 else
2287 cur->PublicID = NULL;
2288 if (nota->SystemID != NULL)
2289 cur->SystemID = xmlStrdup(nota->SystemID);
2290 else
2291 cur->SystemID = NULL;
2292 return(cur);
2293}
2294
2295/**
2296 * xmlCopyNotationTable:
2297 * @table: A notation table
2298 *
2299 * Build a copy of a notation table.
2300 *
2301 * Returns the new xmlNotationTablePtr or NULL in case of error.
2302 */
2303xmlNotationTablePtr
2304xmlCopyNotationTable(xmlNotationTablePtr table) {
2305 return((xmlNotationTablePtr) xmlHashCopy(table,
2306 (xmlHashCopier) xmlCopyNotation));
2307}
Daniel Veillard652327a2003-09-29 18:02:38 +00002308#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002309
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002310#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002311/**
2312 * xmlDumpNotationDecl:
2313 * @buf: the XML buffer output
2314 * @nota: A notation declaration
2315 *
2316 * This will dump the content the notation declaration as an XML DTD definition
2317 */
2318void
2319xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2320 xmlBufferWriteChar(buf, "<!NOTATION ");
2321 xmlBufferWriteCHAR(buf, nota->name);
2322 if (nota->PublicID != NULL) {
2323 xmlBufferWriteChar(buf, " PUBLIC ");
2324 xmlBufferWriteQuotedString(buf, nota->PublicID);
2325 if (nota->SystemID != NULL) {
2326 xmlBufferWriteChar(buf, " ");
2327 xmlBufferWriteCHAR(buf, nota->SystemID);
2328 }
2329 } else {
2330 xmlBufferWriteChar(buf, " SYSTEM ");
2331 xmlBufferWriteCHAR(buf, nota->SystemID);
2332 }
2333 xmlBufferWriteChar(buf, " >\n");
2334}
2335
2336/**
William M. Brack9e660592003-10-20 14:56:06 +00002337 * xmlDumpNotationDeclScan:
2338 * @nota: A notation declaration
2339 * @buf: the XML buffer output
2340 *
2341 * This is called with the hash scan function, and just reverses args
2342 */
2343static void
2344xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2345 xmlDumpNotationDecl(buf, nota);
2346}
2347
2348/**
Owen Taylor3473f882001-02-23 17:55:21 +00002349 * xmlDumpNotationTable:
2350 * @buf: the XML buffer output
2351 * @table: A notation table
2352 *
2353 * This will dump the content of the notation table as an XML DTD definition
2354 */
2355void
2356xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002357 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002358}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002359#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002360
2361/************************************************************************
2362 * *
2363 * IDs *
2364 * *
2365 ************************************************************************/
2366/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002367 * DICT_FREE:
2368 * @str: a string
2369 *
2370 * Free a string if it is not owned by the "dict" dictionnary in the
2371 * current scope
2372 */
2373#define DICT_FREE(str) \
2374 if ((str) && ((!dict) || \
2375 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2376 xmlFree((char *)(str));
2377
2378/**
Owen Taylor3473f882001-02-23 17:55:21 +00002379 * xmlCreateIDTable:
2380 *
2381 * create and initialize an empty id hash table.
2382 *
2383 * Returns the xmlIDTablePtr just created or NULL in case
2384 * of error.
2385 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002386static xmlIDTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002387xmlCreateIDTable(void) {
2388 return(xmlHashCreate(0));
2389}
2390
2391/**
2392 * xmlFreeID:
2393 * @not: A id
2394 *
2395 * Deallocate the memory used by an id definition
2396 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002397static void
Owen Taylor3473f882001-02-23 17:55:21 +00002398xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002399 xmlDictPtr dict = NULL;
2400
Owen Taylor3473f882001-02-23 17:55:21 +00002401 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002402
2403 if (id->doc != NULL)
2404 dict = id->doc->dict;
2405
Owen Taylor3473f882001-02-23 17:55:21 +00002406 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002407 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002408 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002409 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002410 xmlFree(id);
2411}
2412
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002413
Owen Taylor3473f882001-02-23 17:55:21 +00002414/**
2415 * xmlAddID:
2416 * @ctxt: the validation context
2417 * @doc: pointer to the document
2418 * @value: the value name
2419 * @attr: the attribute holding the ID
2420 *
2421 * Register a new id declaration
2422 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002423 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002424 */
2425xmlIDPtr
2426xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2427 xmlAttrPtr attr) {
2428 xmlIDPtr ret;
2429 xmlIDTablePtr table;
2430
2431 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002432 return(NULL);
2433 }
2434 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002435 return(NULL);
2436 }
2437 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002438 return(NULL);
2439 }
2440
2441 /*
2442 * Create the ID table if needed.
2443 */
2444 table = (xmlIDTablePtr) doc->ids;
2445 if (table == NULL)
2446 doc->ids = table = xmlCreateIDTable();
2447 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002448 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002449 "xmlAddID: Table creation failed!\n");
2450 return(NULL);
2451 }
2452
2453 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2454 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002455 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002456 return(NULL);
2457 }
2458
2459 /*
2460 * fill the structure.
2461 */
2462 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002463 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002464 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2465 /*
2466 * Operating in streaming mode, attr is gonna disapear
2467 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002468 if (doc->dict != NULL)
2469 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2470 else
2471 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002472 ret->attr = NULL;
2473 } else {
2474 ret->attr = attr;
2475 ret->name = NULL;
2476 }
2477 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002478
2479 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002480#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002481 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002482 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002483 */
Daniel Veillardd3669b22004-02-25 12:34:55 +00002484 if ((ctxt != NULL) && (ctxt->error != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002485 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2486 "ID %s already defined\n",
2487 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002488 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002489#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002490 xmlFreeID(ret);
2491 return(NULL);
2492 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002493 if (attr != NULL)
2494 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002495 return(ret);
2496}
2497
2498/**
2499 * xmlFreeIDTable:
2500 * @table: An id table
2501 *
2502 * Deallocate the memory used by an ID hash table.
2503 */
2504void
2505xmlFreeIDTable(xmlIDTablePtr table) {
2506 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2507}
2508
2509/**
2510 * xmlIsID:
2511 * @doc: the document
2512 * @elem: the element carrying the attribute
2513 * @attr: the attribute
2514 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002515 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002516 * then this is done if DTD loading has been requested. In the case
2517 * of HTML documents parsed with the HTML parser, then ID detection is
2518 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002519 *
2520 * Returns 0 or 1 depending on the lookup result
2521 */
2522int
2523xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2524 if (doc == NULL) return(0);
2525 if (attr == NULL) return(0);
2526 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2527 return(0);
2528 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard9ba8e382003-10-28 21:31:45 +00002529 if (((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2530 (xmlStrEqual(BAD_CAST "name", attr->name))) &&
2531 ((elem != NULL) && (!xmlStrEqual(elem->name, BAD_CAST "input"))))
Owen Taylor3473f882001-02-23 17:55:21 +00002532 return(1);
2533 return(0);
2534 } else {
2535 xmlAttributePtr attrDecl;
2536
2537 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002538 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002539 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002540 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002541
2542 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002543 if (fullname == NULL)
2544 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002545 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2546 attr->name);
2547 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2548 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2549 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002550 if ((fullname != fn) && (fullname != elem->name))
2551 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002552 } else {
2553 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2554 attr->name);
2555 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2556 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2557 attr->name);
2558 }
Owen Taylor3473f882001-02-23 17:55:21 +00002559
2560 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2561 return(1);
2562 }
2563 return(0);
2564}
2565
2566/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002567 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002568 * @doc: the document
2569 * @attr: the attribute
2570 *
2571 * Remove the given attribute from the ID table maintained internally.
2572 *
2573 * Returns -1 if the lookup failed and 0 otherwise
2574 */
2575int
2576xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002577 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002578 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002579 xmlChar *ID;
2580
2581 if (doc == NULL) return(-1);
2582 if (attr == NULL) return(-1);
2583 table = (xmlIDTablePtr) doc->ids;
2584 if (table == NULL)
2585 return(-1);
2586
2587 if (attr == NULL)
2588 return(-1);
2589 ID = xmlNodeListGetString(doc, attr->children, 1);
2590 if (ID == NULL)
2591 return(-1);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002592 id = xmlHashLookup(table, ID);
2593 if (id == NULL || id->attr != attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002594 xmlFree(ID);
2595 return(-1);
2596 }
2597 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
2598 xmlFree(ID);
2599 return(0);
2600}
2601
2602/**
2603 * xmlGetID:
2604 * @doc: pointer to the document
2605 * @ID: the ID value
2606 *
2607 * Search the attribute declaring the given ID
2608 *
2609 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2610 */
2611xmlAttrPtr
2612xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2613 xmlIDTablePtr table;
2614 xmlIDPtr id;
2615
2616 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002617 return(NULL);
2618 }
2619
2620 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002621 return(NULL);
2622 }
2623
2624 table = (xmlIDTablePtr) doc->ids;
2625 if (table == NULL)
2626 return(NULL);
2627
2628 id = xmlHashLookup(table, ID);
2629 if (id == NULL)
2630 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002631 if (id->attr == NULL) {
2632 /*
2633 * We are operating on a stream, return a well known reference
2634 * since the attribute node doesn't exist anymore
2635 */
2636 return((xmlAttrPtr) doc);
2637 }
Owen Taylor3473f882001-02-23 17:55:21 +00002638 return(id->attr);
2639}
2640
2641/************************************************************************
2642 * *
2643 * Refs *
2644 * *
2645 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002646typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002647{
2648 xmlListPtr l;
2649 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002650} xmlRemoveMemo;
2651
2652typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2653
2654typedef struct xmlValidateMemo_t
2655{
2656 xmlValidCtxtPtr ctxt;
2657 const xmlChar *name;
2658} xmlValidateMemo;
2659
2660typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002661
2662/**
2663 * xmlCreateRefTable:
2664 *
2665 * create and initialize an empty ref hash table.
2666 *
2667 * Returns the xmlRefTablePtr just created or NULL in case
2668 * of error.
2669 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002670static xmlRefTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002671xmlCreateRefTable(void) {
2672 return(xmlHashCreate(0));
2673}
2674
2675/**
2676 * xmlFreeRef:
2677 * @lk: A list link
2678 *
2679 * Deallocate the memory used by a ref definition
2680 */
2681static void
2682xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002683 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2684 if (ref == NULL) return;
2685 if (ref->value != NULL)
2686 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002687 if (ref->name != NULL)
2688 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002689 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002690}
2691
2692/**
2693 * xmlFreeRefList:
2694 * @list_ref: A list of references.
2695 *
2696 * Deallocate the memory used by a list of references
2697 */
2698static void
2699xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002700 if (list_ref == NULL) return;
2701 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002702}
2703
2704/**
2705 * xmlWalkRemoveRef:
2706 * @data: Contents of current link
2707 * @user: Value supplied by the user
2708 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002709 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002710 */
2711static int
2712xmlWalkRemoveRef(const void *data, const void *user)
2713{
Daniel Veillard37721922001-05-04 15:21:12 +00002714 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2715 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2716 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002717
Daniel Veillard37721922001-05-04 15:21:12 +00002718 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2719 xmlListRemoveFirst(ref_list, (void *)data);
2720 return 0;
2721 }
2722 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002723}
2724
2725/**
Daniel Veillard770075b2004-02-25 10:44:30 +00002726 * xmlDummyCompare
2727 * @data0: Value supplied by the user
2728 * @data1: Value supplied by the user
2729 *
2730 * Do nothing, return 0. Used to create unordered lists.
2731 */
2732static int
Daniel Veillardf54cd532004-02-25 11:52:31 +00002733xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2734 const void *data1 ATTRIBUTE_UNUSED)
Daniel Veillard770075b2004-02-25 10:44:30 +00002735{
2736 return (0);
2737}
2738
2739/**
Owen Taylor3473f882001-02-23 17:55:21 +00002740 * xmlAddRef:
2741 * @ctxt: the validation context
2742 * @doc: pointer to the document
2743 * @value: the value name
2744 * @attr: the attribute holding the Ref
2745 *
2746 * Register a new ref declaration
2747 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002748 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002749 */
2750xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002751xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002752 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002753 xmlRefPtr ret;
2754 xmlRefTablePtr table;
2755 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002756
Daniel Veillard37721922001-05-04 15:21:12 +00002757 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002758 return(NULL);
2759 }
2760 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002761 return(NULL);
2762 }
2763 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002764 return(NULL);
2765 }
Owen Taylor3473f882001-02-23 17:55:21 +00002766
Daniel Veillard37721922001-05-04 15:21:12 +00002767 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002768 * Create the Ref table if needed.
2769 */
Daniel Veillard37721922001-05-04 15:21:12 +00002770 table = (xmlRefTablePtr) doc->refs;
2771 if (table == NULL)
2772 doc->refs = table = xmlCreateRefTable();
2773 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002774 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002775 "xmlAddRef: Table creation failed!\n");
2776 return(NULL);
2777 }
Owen Taylor3473f882001-02-23 17:55:21 +00002778
Daniel Veillard37721922001-05-04 15:21:12 +00002779 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2780 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002781 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002782 return(NULL);
2783 }
Owen Taylor3473f882001-02-23 17:55:21 +00002784
Daniel Veillard37721922001-05-04 15:21:12 +00002785 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002786 * fill the structure.
2787 */
Daniel Veillard37721922001-05-04 15:21:12 +00002788 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002789 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2790 /*
2791 * Operating in streaming mode, attr is gonna disapear
2792 */
2793 ret->name = xmlStrdup(attr->name);
2794 ret->attr = NULL;
2795 } else {
2796 ret->name = NULL;
2797 ret->attr = attr;
2798 }
2799 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002800
Daniel Veillard37721922001-05-04 15:21:12 +00002801 /* To add a reference :-
2802 * References are maintained as a list of references,
2803 * Lookup the entry, if no entry create new nodelist
2804 * Add the owning node to the NodeList
2805 * Return the ref
2806 */
Owen Taylor3473f882001-02-23 17:55:21 +00002807
Daniel Veillard37721922001-05-04 15:21:12 +00002808 if (NULL == (ref_list = xmlHashLookup(table, value))) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002809 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002810 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2811 "xmlAddRef: Reference list creation failed!\n",
2812 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002813 return(NULL);
2814 }
2815 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2816 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002817 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2818 "xmlAddRef: Reference list insertion failed!\n",
2819 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002820 return(NULL);
2821 }
2822 }
Daniel Veillard965983a2004-02-17 16:30:24 +00002823/* xmlListInsert(ref_list, ret); */
2824 xmlListAppend(ref_list, ret);
Daniel Veillard37721922001-05-04 15:21:12 +00002825 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002826}
2827
2828/**
2829 * xmlFreeRefTable:
2830 * @table: An ref table
2831 *
2832 * Deallocate the memory used by an Ref hash table.
2833 */
2834void
2835xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002836 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002837}
2838
2839/**
2840 * xmlIsRef:
2841 * @doc: the document
2842 * @elem: the element carrying the attribute
2843 * @attr: the attribute
2844 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002845 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00002846 * then this is simple, otherwise we use an heuristic: name Ref (upper
2847 * or lowercase).
2848 *
2849 * Returns 0 or 1 depending on the lookup result
2850 */
2851int
2852xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002853 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2854 return(0);
2855 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2856 /* TODO @@@ */
2857 return(0);
2858 } else {
2859 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00002860
Daniel Veillard37721922001-05-04 15:21:12 +00002861 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2862 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2863 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2864 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002865
Daniel Veillard37721922001-05-04 15:21:12 +00002866 if ((attrDecl != NULL) &&
2867 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2868 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2869 return(1);
2870 }
2871 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002872}
2873
2874/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002875 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00002876 * @doc: the document
2877 * @attr: the attribute
2878 *
2879 * Remove the given attribute from the Ref table maintained internally.
2880 *
2881 * Returns -1 if the lookup failed and 0 otherwise
2882 */
2883int
2884xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002885 xmlListPtr ref_list;
2886 xmlRefTablePtr table;
2887 xmlChar *ID;
2888 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00002889
Daniel Veillard37721922001-05-04 15:21:12 +00002890 if (doc == NULL) return(-1);
2891 if (attr == NULL) return(-1);
2892 table = (xmlRefTablePtr) doc->refs;
2893 if (table == NULL)
2894 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002895
Daniel Veillard37721922001-05-04 15:21:12 +00002896 if (attr == NULL)
2897 return(-1);
2898 ID = xmlNodeListGetString(doc, attr->children, 1);
2899 if (ID == NULL)
2900 return(-1);
2901 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00002902
Daniel Veillard37721922001-05-04 15:21:12 +00002903 if(ref_list == NULL) {
2904 xmlFree(ID);
2905 return (-1);
2906 }
2907 /* At this point, ref_list refers to a list of references which
2908 * have the same key as the supplied attr. Our list of references
2909 * is ordered by reference address and we don't have that information
2910 * here to use when removing. We'll have to walk the list and
2911 * check for a matching attribute, when we find one stop the walk
2912 * and remove the entry.
2913 * The list is ordered by reference, so that means we don't have the
2914 * key. Passing the list and the reference to the walker means we
2915 * will have enough data to be able to remove the entry.
2916 */
2917 target.l = ref_list;
2918 target.ap = attr;
2919
2920 /* Remove the supplied attr from our list */
2921 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00002922
Daniel Veillard37721922001-05-04 15:21:12 +00002923 /*If the list is empty then remove the list entry in the hash */
2924 if (xmlListEmpty(ref_list))
2925 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2926 xmlFreeRefList);
2927 xmlFree(ID);
2928 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002929}
2930
2931/**
2932 * xmlGetRefs:
2933 * @doc: pointer to the document
2934 * @ID: the ID value
2935 *
2936 * Find the set of references for the supplied ID.
2937 *
2938 * Returns NULL if not found, otherwise node set for the ID.
2939 */
2940xmlListPtr
2941xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00002942 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00002943
Daniel Veillard37721922001-05-04 15:21:12 +00002944 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002945 return(NULL);
2946 }
Owen Taylor3473f882001-02-23 17:55:21 +00002947
Daniel Veillard37721922001-05-04 15:21:12 +00002948 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002949 return(NULL);
2950 }
Owen Taylor3473f882001-02-23 17:55:21 +00002951
Daniel Veillard37721922001-05-04 15:21:12 +00002952 table = (xmlRefTablePtr) doc->refs;
2953 if (table == NULL)
2954 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002955
Daniel Veillard37721922001-05-04 15:21:12 +00002956 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00002957}
2958
2959/************************************************************************
2960 * *
2961 * Routines for validity checking *
2962 * *
2963 ************************************************************************/
2964
2965/**
2966 * xmlGetDtdElementDesc:
2967 * @dtd: a pointer to the DtD to search
2968 * @name: the element name
2969 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002970 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002971 *
2972 * returns the xmlElementPtr if found or NULL
2973 */
2974
2975xmlElementPtr
2976xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2977 xmlElementTablePtr table;
2978 xmlElementPtr cur;
2979 xmlChar *uqname = NULL, *prefix = NULL;
2980
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002981 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002982 if (dtd->elements == NULL)
2983 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002984 table = (xmlElementTablePtr) dtd->elements;
2985
2986 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002987 if (uqname != NULL)
2988 name = uqname;
2989 cur = xmlHashLookup2(table, name, prefix);
2990 if (prefix != NULL) xmlFree(prefix);
2991 if (uqname != NULL) xmlFree(uqname);
2992 return(cur);
2993}
2994/**
2995 * xmlGetDtdElementDesc2:
2996 * @dtd: a pointer to the DtD to search
2997 * @name: the element name
2998 * @create: create an empty description if not found
2999 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003000 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00003001 *
3002 * returns the xmlElementPtr if found or NULL
3003 */
3004
Daniel Veillard86fd5a72001-12-13 14:55:21 +00003005static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00003006xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3007 xmlElementTablePtr table;
3008 xmlElementPtr cur;
3009 xmlChar *uqname = NULL, *prefix = NULL;
3010
3011 if (dtd == NULL) return(NULL);
3012 if (dtd->elements == NULL) {
3013 if (!create)
3014 return(NULL);
3015 /*
3016 * Create the Element table if needed.
3017 */
3018 table = (xmlElementTablePtr) dtd->elements;
3019 if (table == NULL) {
3020 table = xmlCreateElementTable();
3021 dtd->elements = (void *) table;
3022 }
3023 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003024 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003025 return(NULL);
3026 }
3027 }
3028 table = (xmlElementTablePtr) dtd->elements;
3029
3030 uqname = xmlSplitQName2(name, &prefix);
3031 if (uqname != NULL)
3032 name = uqname;
3033 cur = xmlHashLookup2(table, name, prefix);
3034 if ((cur == NULL) && (create)) {
3035 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3036 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003037 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003038 return(NULL);
3039 }
3040 memset(cur, 0, sizeof(xmlElement));
3041 cur->type = XML_ELEMENT_DECL;
3042
3043 /*
3044 * fill the structure.
3045 */
3046 cur->name = xmlStrdup(name);
3047 cur->prefix = xmlStrdup(prefix);
3048 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3049
3050 xmlHashAddEntry2(table, name, prefix, cur);
3051 }
3052 if (prefix != NULL) xmlFree(prefix);
3053 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003054 return(cur);
3055}
3056
3057/**
3058 * xmlGetDtdQElementDesc:
3059 * @dtd: a pointer to the DtD to search
3060 * @name: the element name
3061 * @prefix: the element namespace prefix
3062 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003063 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003064 *
3065 * returns the xmlElementPtr if found or NULL
3066 */
3067
Daniel Veillard48da9102001-08-07 01:10:10 +00003068xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003069xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3070 const xmlChar *prefix) {
3071 xmlElementTablePtr table;
3072
3073 if (dtd == NULL) return(NULL);
3074 if (dtd->elements == NULL) return(NULL);
3075 table = (xmlElementTablePtr) dtd->elements;
3076
3077 return(xmlHashLookup2(table, name, prefix));
3078}
3079
3080/**
3081 * xmlGetDtdAttrDesc:
3082 * @dtd: a pointer to the DtD to search
3083 * @elem: the element name
3084 * @name: the attribute name
3085 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003086 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003087 * this element.
3088 *
3089 * returns the xmlAttributePtr if found or NULL
3090 */
3091
3092xmlAttributePtr
3093xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3094 xmlAttributeTablePtr table;
3095 xmlAttributePtr cur;
3096 xmlChar *uqname = NULL, *prefix = NULL;
3097
3098 if (dtd == NULL) return(NULL);
3099 if (dtd->attributes == NULL) return(NULL);
3100
3101 table = (xmlAttributeTablePtr) dtd->attributes;
3102 if (table == NULL)
3103 return(NULL);
3104
3105 uqname = xmlSplitQName2(name, &prefix);
3106
3107 if (uqname != NULL) {
3108 cur = xmlHashLookup3(table, uqname, prefix, elem);
3109 if (prefix != NULL) xmlFree(prefix);
3110 if (uqname != NULL) xmlFree(uqname);
3111 } else
3112 cur = xmlHashLookup3(table, name, NULL, elem);
3113 return(cur);
3114}
3115
3116/**
3117 * xmlGetDtdQAttrDesc:
3118 * @dtd: a pointer to the DtD to search
3119 * @elem: the element name
3120 * @name: the attribute name
3121 * @prefix: the attribute namespace prefix
3122 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003123 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003124 * this element.
3125 *
3126 * returns the xmlAttributePtr if found or NULL
3127 */
3128
Daniel Veillard48da9102001-08-07 01:10:10 +00003129xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003130xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3131 const xmlChar *prefix) {
3132 xmlAttributeTablePtr table;
3133
3134 if (dtd == NULL) return(NULL);
3135 if (dtd->attributes == NULL) return(NULL);
3136 table = (xmlAttributeTablePtr) dtd->attributes;
3137
3138 return(xmlHashLookup3(table, name, prefix, elem));
3139}
3140
3141/**
3142 * xmlGetDtdNotationDesc:
3143 * @dtd: a pointer to the DtD to search
3144 * @name: the notation name
3145 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003146 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003147 *
3148 * returns the xmlNotationPtr if found or NULL
3149 */
3150
3151xmlNotationPtr
3152xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3153 xmlNotationTablePtr table;
3154
3155 if (dtd == NULL) return(NULL);
3156 if (dtd->notations == NULL) return(NULL);
3157 table = (xmlNotationTablePtr) dtd->notations;
3158
3159 return(xmlHashLookup(table, name));
3160}
3161
Daniel Veillardf54cd532004-02-25 11:52:31 +00003162#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003163/**
3164 * xmlValidateNotationUse:
3165 * @ctxt: the validation context
3166 * @doc: the document
3167 * @notationName: the notation name to check
3168 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003169 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003170 * - [ VC: Notation Declared ]
3171 *
3172 * returns 1 if valid or 0 otherwise
3173 */
3174
3175int
3176xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3177 const xmlChar *notationName) {
3178 xmlNotationPtr notaDecl;
3179 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3180
3181 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3182 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3183 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3184
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003185 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003186 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3187 "NOTATION %s is not declared\n",
3188 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003189 return(0);
3190 }
3191 return(1);
3192}
Daniel Veillardf54cd532004-02-25 11:52:31 +00003193#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003194
3195/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003196 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003197 * @doc: the document
3198 * @name: the element name
3199 *
3200 * Search in the DtDs whether an element accept Mixed content (or ANY)
3201 * basically if it is supposed to accept text childs
3202 *
3203 * returns 0 if no, 1 if yes, and -1 if no element description is available
3204 */
3205
3206int
3207xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3208 xmlElementPtr elemDecl;
3209
3210 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3211
3212 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3213 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3214 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3215 if (elemDecl == NULL) return(-1);
3216 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003217 case XML_ELEMENT_TYPE_UNDEFINED:
3218 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003219 case XML_ELEMENT_TYPE_ELEMENT:
3220 return(0);
3221 case XML_ELEMENT_TYPE_EMPTY:
3222 /*
3223 * return 1 for EMPTY since we want VC error to pop up
3224 * on <empty> </empty> for example
3225 */
3226 case XML_ELEMENT_TYPE_ANY:
3227 case XML_ELEMENT_TYPE_MIXED:
3228 return(1);
3229 }
3230 return(1);
3231}
3232
Daniel Veillard4432df22003-09-28 18:58:27 +00003233#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003234/**
3235 * xmlValidateNameValue:
3236 * @value: an Name value
3237 *
3238 * Validate that the given value match Name production
3239 *
3240 * returns 1 if valid or 0 otherwise
3241 */
3242
Daniel Veillard9b731d72002-04-14 12:56:08 +00003243int
Owen Taylor3473f882001-02-23 17:55:21 +00003244xmlValidateNameValue(const xmlChar *value) {
3245 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003246 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003247
3248 if (value == NULL) return(0);
3249 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003250 val = xmlStringCurrentChar(NULL, cur, &len);
3251 cur += len;
3252 if (!IS_LETTER(val) && (val != '_') &&
3253 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003254 return(0);
3255 }
3256
Daniel Veillardd8224e02002-01-13 15:43:22 +00003257 val = xmlStringCurrentChar(NULL, cur, &len);
3258 cur += len;
3259 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3260 (val == '.') || (val == '-') ||
3261 (val == '_') || (val == ':') ||
3262 (IS_COMBINING(val)) ||
3263 (IS_EXTENDER(val))) {
3264 val = xmlStringCurrentChar(NULL, cur, &len);
3265 cur += len;
3266 }
Owen Taylor3473f882001-02-23 17:55:21 +00003267
Daniel Veillardd8224e02002-01-13 15:43:22 +00003268 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003269
3270 return(1);
3271}
3272
3273/**
3274 * xmlValidateNamesValue:
3275 * @value: an Names value
3276 *
3277 * Validate that the given value match Names production
3278 *
3279 * returns 1 if valid or 0 otherwise
3280 */
3281
Daniel Veillard9b731d72002-04-14 12:56:08 +00003282int
Owen Taylor3473f882001-02-23 17:55:21 +00003283xmlValidateNamesValue(const xmlChar *value) {
3284 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003285 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003286
3287 if (value == NULL) return(0);
3288 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003289 val = xmlStringCurrentChar(NULL, cur, &len);
3290 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003291
Daniel Veillardd8224e02002-01-13 15:43:22 +00003292 if (!IS_LETTER(val) && (val != '_') &&
3293 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003294 return(0);
3295 }
3296
Daniel Veillardd8224e02002-01-13 15:43:22 +00003297 val = xmlStringCurrentChar(NULL, cur, &len);
3298 cur += len;
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;
Owen Taylor3473f882001-02-23 17:55:21 +00003306 }
3307
Daniel Veillardd8224e02002-01-13 15:43:22 +00003308 while (IS_BLANK(val)) {
3309 while (IS_BLANK(val)) {
3310 val = xmlStringCurrentChar(NULL, cur, &len);
3311 cur += len;
3312 }
3313
3314 if (!IS_LETTER(val) && (val != '_') &&
3315 (val != ':')) {
3316 return(0);
3317 }
3318 val = xmlStringCurrentChar(NULL, cur, &len);
3319 cur += len;
3320
3321 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3322 (val == '.') || (val == '-') ||
3323 (val == '_') || (val == ':') ||
3324 (IS_COMBINING(val)) ||
3325 (IS_EXTENDER(val))) {
3326 val = xmlStringCurrentChar(NULL, cur, &len);
3327 cur += len;
3328 }
3329 }
3330
3331 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003332
3333 return(1);
3334}
3335
3336/**
3337 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003338 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003339 *
3340 * Validate that the given value match Nmtoken production
3341 *
3342 * [ VC: Name Token ]
3343 *
3344 * returns 1 if valid or 0 otherwise
3345 */
3346
Daniel Veillard9b731d72002-04-14 12:56:08 +00003347int
Owen Taylor3473f882001-02-23 17:55:21 +00003348xmlValidateNmtokenValue(const xmlChar *value) {
3349 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003350 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003351
3352 if (value == NULL) return(0);
3353 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003354 val = xmlStringCurrentChar(NULL, cur, &len);
3355 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003356
Daniel Veillardd8224e02002-01-13 15:43:22 +00003357 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3358 (val != '.') && (val != '-') &&
3359 (val != '_') && (val != ':') &&
3360 (!IS_COMBINING(val)) &&
3361 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003362 return(0);
3363
Daniel Veillardd8224e02002-01-13 15:43:22 +00003364 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3365 (val == '.') || (val == '-') ||
3366 (val == '_') || (val == ':') ||
3367 (IS_COMBINING(val)) ||
3368 (IS_EXTENDER(val))) {
3369 val = xmlStringCurrentChar(NULL, cur, &len);
3370 cur += len;
3371 }
Owen Taylor3473f882001-02-23 17:55:21 +00003372
Daniel Veillardd8224e02002-01-13 15:43:22 +00003373 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003374
3375 return(1);
3376}
3377
3378/**
3379 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003380 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003381 *
3382 * Validate that the given value match Nmtokens production
3383 *
3384 * [ VC: Name Token ]
3385 *
3386 * returns 1 if valid or 0 otherwise
3387 */
3388
Daniel Veillard9b731d72002-04-14 12:56:08 +00003389int
Owen Taylor3473f882001-02-23 17:55:21 +00003390xmlValidateNmtokensValue(const xmlChar *value) {
3391 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003392 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003393
3394 if (value == NULL) return(0);
3395 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003396 val = xmlStringCurrentChar(NULL, cur, &len);
3397 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003398
Daniel Veillardd8224e02002-01-13 15:43:22 +00003399 while (IS_BLANK(val)) {
3400 val = xmlStringCurrentChar(NULL, cur, &len);
3401 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003402 }
3403
Daniel Veillardd8224e02002-01-13 15:43:22 +00003404 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3405 (val != '.') && (val != '-') &&
3406 (val != '_') && (val != ':') &&
3407 (!IS_COMBINING(val)) &&
3408 (!IS_EXTENDER(val)))
3409 return(0);
3410
3411 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3412 (val == '.') || (val == '-') ||
3413 (val == '_') || (val == ':') ||
3414 (IS_COMBINING(val)) ||
3415 (IS_EXTENDER(val))) {
3416 val = xmlStringCurrentChar(NULL, cur, &len);
3417 cur += len;
3418 }
3419
3420 while (IS_BLANK(val)) {
3421 while (IS_BLANK(val)) {
3422 val = xmlStringCurrentChar(NULL, cur, &len);
3423 cur += len;
3424 }
3425 if (val == 0) return(1);
3426
3427 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3428 (val != '.') && (val != '-') &&
3429 (val != '_') && (val != ':') &&
3430 (!IS_COMBINING(val)) &&
3431 (!IS_EXTENDER(val)))
3432 return(0);
3433
3434 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3435 (val == '.') || (val == '-') ||
3436 (val == '_') || (val == ':') ||
3437 (IS_COMBINING(val)) ||
3438 (IS_EXTENDER(val))) {
3439 val = xmlStringCurrentChar(NULL, cur, &len);
3440 cur += len;
3441 }
3442 }
3443
3444 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003445
3446 return(1);
3447}
3448
3449/**
3450 * xmlValidateNotationDecl:
3451 * @ctxt: the validation context
3452 * @doc: a document instance
3453 * @nota: a notation definition
3454 *
3455 * Try to validate a single notation definition
3456 * basically it does the following checks as described by the
3457 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003458 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003459 * But this function get called anyway ...
3460 *
3461 * returns 1 if valid or 0 otherwise
3462 */
3463
3464int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003465xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3466 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003467 int ret = 1;
3468
3469 return(ret);
3470}
3471
3472/**
3473 * xmlValidateAttributeValue:
3474 * @type: an attribute type
3475 * @value: an attribute value
3476 *
3477 * Validate that the given attribute value match the proper production
3478 *
3479 * [ VC: ID ]
3480 * Values of type ID must match the Name production....
3481 *
3482 * [ VC: IDREF ]
3483 * Values of type IDREF must match the Name production, and values
3484 * of type IDREFS must match Names ...
3485 *
3486 * [ VC: Entity Name ]
3487 * Values of type ENTITY must match the Name production, values
3488 * of type ENTITIES must match Names ...
3489 *
3490 * [ VC: Name Token ]
3491 * Values of type NMTOKEN must match the Nmtoken production; values
3492 * of type NMTOKENS must match Nmtokens.
3493 *
3494 * returns 1 if valid or 0 otherwise
3495 */
3496
3497int
3498xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3499 switch (type) {
3500 case XML_ATTRIBUTE_ENTITIES:
3501 case XML_ATTRIBUTE_IDREFS:
3502 return(xmlValidateNamesValue(value));
3503 case XML_ATTRIBUTE_ENTITY:
3504 case XML_ATTRIBUTE_IDREF:
3505 case XML_ATTRIBUTE_ID:
3506 case XML_ATTRIBUTE_NOTATION:
3507 return(xmlValidateNameValue(value));
3508 case XML_ATTRIBUTE_NMTOKENS:
3509 case XML_ATTRIBUTE_ENUMERATION:
3510 return(xmlValidateNmtokensValue(value));
3511 case XML_ATTRIBUTE_NMTOKEN:
3512 return(xmlValidateNmtokenValue(value));
3513 case XML_ATTRIBUTE_CDATA:
3514 break;
3515 }
3516 return(1);
3517}
3518
3519/**
3520 * xmlValidateAttributeValue2:
3521 * @ctxt: the validation context
3522 * @doc: the document
3523 * @name: the attribute name (used for error reporting only)
3524 * @type: the attribute type
3525 * @value: the attribute value
3526 *
3527 * Validate that the given attribute value match a given type.
3528 * This typically cannot be done before having finished parsing
3529 * the subsets.
3530 *
3531 * [ VC: IDREF ]
3532 * Values of type IDREF must match one of the declared IDs
3533 * Values of type IDREFS must match a sequence of the declared IDs
3534 * each Name must match the value of an ID attribute on some element
3535 * in the XML document; i.e. IDREF values must match the value of
3536 * some ID attribute
3537 *
3538 * [ VC: Entity Name ]
3539 * Values of type ENTITY must match one declared entity
3540 * Values of type ENTITIES must match a sequence of declared entities
3541 *
3542 * [ VC: Notation Attributes ]
3543 * all notation names in the declaration must be declared.
3544 *
3545 * returns 1 if valid or 0 otherwise
3546 */
3547
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003548static int
Owen Taylor3473f882001-02-23 17:55:21 +00003549xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3550 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3551 int ret = 1;
3552 switch (type) {
3553 case XML_ATTRIBUTE_IDREFS:
3554 case XML_ATTRIBUTE_IDREF:
3555 case XML_ATTRIBUTE_ID:
3556 case XML_ATTRIBUTE_NMTOKENS:
3557 case XML_ATTRIBUTE_ENUMERATION:
3558 case XML_ATTRIBUTE_NMTOKEN:
3559 case XML_ATTRIBUTE_CDATA:
3560 break;
3561 case XML_ATTRIBUTE_ENTITY: {
3562 xmlEntityPtr ent;
3563
3564 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003565 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003566 if ((ent == NULL) && (doc->standalone == 1)) {
3567 doc->standalone = 0;
3568 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003569 }
Owen Taylor3473f882001-02-23 17:55:21 +00003570 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003571 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3572 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003573 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003574 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003575 ret = 0;
3576 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003577 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3578 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003579 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003580 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003581 ret = 0;
3582 }
3583 break;
3584 }
3585 case XML_ATTRIBUTE_ENTITIES: {
3586 xmlChar *dup, *nam = NULL, *cur, save;
3587 xmlEntityPtr ent;
3588
3589 dup = xmlStrdup(value);
3590 if (dup == NULL)
3591 return(0);
3592 cur = dup;
3593 while (*cur != 0) {
3594 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003595 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003596 save = *cur;
3597 *cur = 0;
3598 ent = xmlGetDocEntity(doc, nam);
3599 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003600 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3601 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003602 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003603 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003604 ret = 0;
3605 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003606 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3607 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003608 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003609 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003610 ret = 0;
3611 }
3612 if (save == 0)
3613 break;
3614 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003615 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003616 }
3617 xmlFree(dup);
3618 break;
3619 }
3620 case XML_ATTRIBUTE_NOTATION: {
3621 xmlNotationPtr nota;
3622
3623 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3624 if ((nota == NULL) && (doc->extSubset != NULL))
3625 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3626
3627 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003628 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3629 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003630 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003631 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003632 ret = 0;
3633 }
3634 break;
3635 }
3636 }
3637 return(ret);
3638}
3639
3640/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003641 * xmlValidCtxtNormalizeAttributeValue:
3642 * @ctxt: the validation context
3643 * @doc: the document
3644 * @elem: the parent
3645 * @name: the attribute name
3646 * @value: the attribute value
3647 * @ctxt: the validation context or NULL
3648 *
3649 * Does the validation related extra step of the normalization of attribute
3650 * values:
3651 *
3652 * If the declared value is not CDATA, then the XML processor must further
3653 * process the normalized attribute value by discarding any leading and
3654 * trailing space (#x20) characters, and by replacing sequences of space
3655 * (#x20) characters by single space (#x20) character.
3656 *
3657 * Also check VC: Standalone Document Declaration in P32, and update
3658 * ctxt->valid accordingly
3659 *
3660 * returns a new normalized string if normalization is needed, NULL otherwise
3661 * the caller must free the returned value.
3662 */
3663
3664xmlChar *
3665xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3666 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3667 xmlChar *ret, *dst;
3668 const xmlChar *src;
3669 xmlAttributePtr attrDecl = NULL;
3670 int extsubset = 0;
3671
3672 if (doc == NULL) return(NULL);
3673 if (elem == NULL) return(NULL);
3674 if (name == NULL) return(NULL);
3675 if (value == NULL) return(NULL);
3676
3677 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003678 xmlChar fn[50];
3679 xmlChar *fullname;
3680
3681 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3682 if (fullname == NULL)
3683 return(0);
3684 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003685 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003686 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003687 if (attrDecl != NULL)
3688 extsubset = 1;
3689 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003690 if ((fullname != fn) && (fullname != elem->name))
3691 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003692 }
3693 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3694 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3695 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3696 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3697 if (attrDecl != NULL)
3698 extsubset = 1;
3699 }
3700
3701 if (attrDecl == NULL)
3702 return(NULL);
3703 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3704 return(NULL);
3705
3706 ret = xmlStrdup(value);
3707 if (ret == NULL)
3708 return(NULL);
3709 src = value;
3710 dst = ret;
3711 while (*src == 0x20) src++;
3712 while (*src != 0) {
3713 if (*src == 0x20) {
3714 while (*src == 0x20) src++;
3715 if (*src != 0)
3716 *dst++ = 0x20;
3717 } else {
3718 *dst++ = *src++;
3719 }
3720 }
3721 *dst = 0;
3722 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003723 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003724"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003725 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003726 ctxt->valid = 0;
3727 }
3728 return(ret);
3729}
3730
3731/**
Owen Taylor3473f882001-02-23 17:55:21 +00003732 * xmlValidNormalizeAttributeValue:
3733 * @doc: the document
3734 * @elem: the parent
3735 * @name: the attribute name
3736 * @value: the attribute value
3737 *
3738 * Does the validation related extra step of the normalization of attribute
3739 * values:
3740 *
3741 * If the declared value is not CDATA, then the XML processor must further
3742 * process the normalized attribute value by discarding any leading and
3743 * trailing space (#x20) characters, and by replacing sequences of space
3744 * (#x20) characters by single space (#x20) character.
3745 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003746 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003747 * the caller must free the returned value.
3748 */
3749
3750xmlChar *
3751xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3752 const xmlChar *name, const xmlChar *value) {
3753 xmlChar *ret, *dst;
3754 const xmlChar *src;
3755 xmlAttributePtr attrDecl = NULL;
3756
3757 if (doc == NULL) return(NULL);
3758 if (elem == NULL) return(NULL);
3759 if (name == NULL) return(NULL);
3760 if (value == NULL) return(NULL);
3761
3762 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003763 xmlChar fn[50];
3764 xmlChar *fullname;
3765
3766 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3767 if (fullname == NULL)
3768 return(0);
3769 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003770 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003771 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3772 if ((fullname != fn) && (fullname != elem->name))
3773 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003774 }
3775 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3776 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3777 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3778
3779 if (attrDecl == NULL)
3780 return(NULL);
3781 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3782 return(NULL);
3783
3784 ret = xmlStrdup(value);
3785 if (ret == NULL)
3786 return(NULL);
3787 src = value;
3788 dst = ret;
3789 while (*src == 0x20) src++;
3790 while (*src != 0) {
3791 if (*src == 0x20) {
3792 while (*src == 0x20) src++;
3793 if (*src != 0)
3794 *dst++ = 0x20;
3795 } else {
3796 *dst++ = *src++;
3797 }
3798 }
3799 *dst = 0;
3800 return(ret);
3801}
3802
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003803static void
Owen Taylor3473f882001-02-23 17:55:21 +00003804xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003805 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003806 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3807}
3808
3809/**
3810 * xmlValidateAttributeDecl:
3811 * @ctxt: the validation context
3812 * @doc: a document instance
3813 * @attr: an attribute definition
3814 *
3815 * Try to validate a single attribute definition
3816 * basically it does the following checks as described by the
3817 * XML-1.0 recommendation:
3818 * - [ VC: Attribute Default Legal ]
3819 * - [ VC: Enumeration ]
3820 * - [ VC: ID Attribute Default ]
3821 *
3822 * The ID/IDREF uniqueness and matching are done separately
3823 *
3824 * returns 1 if valid or 0 otherwise
3825 */
3826
3827int
3828xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3829 xmlAttributePtr attr) {
3830 int ret = 1;
3831 int val;
3832 CHECK_DTD;
3833 if(attr == NULL) return(1);
3834
3835 /* Attribute Default Legal */
3836 /* Enumeration */
3837 if (attr->defaultValue != NULL) {
3838 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3839 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003840 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003841 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003842 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003843 }
3844 ret &= val;
3845 }
3846
3847 /* ID Attribute Default */
3848 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3849 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3850 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003851 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003852 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003853 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003854 ret = 0;
3855 }
3856
3857 /* One ID per Element Type */
3858 if (attr->atype == XML_ATTRIBUTE_ID) {
3859 int nbId;
3860
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003861 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00003862 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3863 attr->elem);
3864 if (elem != NULL) {
3865 nbId = xmlScanIDAttributeDecl(NULL, elem);
3866 } else {
3867 xmlAttributeTablePtr table;
3868
3869 /*
3870 * The attribute may be declared in the internal subset and the
3871 * element in the external subset.
3872 */
3873 nbId = 0;
3874 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3875 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3876 xmlValidateAttributeIdCallback, &nbId);
3877 }
3878 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003879
3880 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003881 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3882 attr->elem, nbId, attr->name);
3883 } else if (doc->extSubset != NULL) {
3884 int extId = 0;
3885 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3886 if (elem != NULL) {
3887 extId = xmlScanIDAttributeDecl(NULL, elem);
3888 }
3889 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003890 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003891 "Element %s has %d ID attribute defined in the external subset : %s\n",
3892 attr->elem, extId, attr->name);
3893 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003894 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003895"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003896 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003897 }
3898 }
3899 }
3900
3901 /* Validity Constraint: Enumeration */
3902 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3903 xmlEnumerationPtr tree = attr->tree;
3904 while (tree != NULL) {
3905 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3906 tree = tree->next;
3907 }
3908 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003909 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003910"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003911 attr->defaultValue, attr->name, attr->elem);
3912 ret = 0;
3913 }
3914 }
3915
3916 return(ret);
3917}
3918
3919/**
3920 * xmlValidateElementDecl:
3921 * @ctxt: the validation context
3922 * @doc: a document instance
3923 * @elem: an element definition
3924 *
3925 * Try to validate a single element definition
3926 * basically it does the following checks as described by the
3927 * XML-1.0 recommendation:
3928 * - [ VC: One ID per Element Type ]
3929 * - [ VC: No Duplicate Types ]
3930 * - [ VC: Unique Element Type Declaration ]
3931 *
3932 * returns 1 if valid or 0 otherwise
3933 */
3934
3935int
3936xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3937 xmlElementPtr elem) {
3938 int ret = 1;
3939 xmlElementPtr tst;
3940
3941 CHECK_DTD;
3942
3943 if (elem == NULL) return(1);
3944
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003945#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00003946#ifdef LIBXML_REGEXP_ENABLED
3947 /* Build the regexp associated to the content model */
3948 ret = xmlValidBuildContentModel(ctxt, elem);
3949#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003950#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00003951
Owen Taylor3473f882001-02-23 17:55:21 +00003952 /* No Duplicate Types */
3953 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3954 xmlElementContentPtr cur, next;
3955 const xmlChar *name;
3956
3957 cur = elem->content;
3958 while (cur != NULL) {
3959 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3960 if (cur->c1 == NULL) break;
3961 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3962 name = cur->c1->name;
3963 next = cur->c2;
3964 while (next != NULL) {
3965 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00003966 if ((xmlStrEqual(next->name, name)) &&
3967 (xmlStrEqual(next->prefix, cur->prefix))) {
3968 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003969 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00003970 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003971 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003972 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003973 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003974 "Definition of %s has duplicate references of %s:%s\n",
3975 elem->name, cur->prefix, name);
3976 }
Owen Taylor3473f882001-02-23 17:55:21 +00003977 ret = 0;
3978 }
3979 break;
3980 }
3981 if (next->c1 == NULL) break;
3982 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00003983 if ((xmlStrEqual(next->c1->name, name)) &&
3984 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
3985 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003986 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003987 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003988 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003989 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003990 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003991 "Definition of %s has duplicate references to %s:%s\n",
3992 elem->name, cur->prefix, name);
3993 }
Owen Taylor3473f882001-02-23 17:55:21 +00003994 ret = 0;
3995 }
3996 next = next->c2;
3997 }
3998 }
3999 cur = cur->c2;
4000 }
4001 }
4002
4003 /* VC: Unique Element Type Declaration */
4004 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004005 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004006 ((tst->prefix == elem->prefix) ||
4007 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004008 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004009 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4010 "Redefinition of element %s\n",
4011 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004012 ret = 0;
4013 }
4014 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004015 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004016 ((tst->prefix == elem->prefix) ||
4017 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004018 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004019 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4020 "Redefinition of element %s\n",
4021 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004022 ret = 0;
4023 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004024 /* One ID per Element Type
4025 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004026 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4027 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004028 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004029 return(ret);
4030}
4031
4032/**
4033 * xmlValidateOneAttribute:
4034 * @ctxt: the validation context
4035 * @doc: a document instance
4036 * @elem: an element instance
4037 * @attr: an attribute instance
4038 * @value: the attribute value (without entities processing)
4039 *
4040 * Try to validate a single attribute for an element
4041 * basically it does the following checks as described by the
4042 * XML-1.0 recommendation:
4043 * - [ VC: Attribute Value Type ]
4044 * - [ VC: Fixed Attribute Default ]
4045 * - [ VC: Entity Name ]
4046 * - [ VC: Name Token ]
4047 * - [ VC: ID ]
4048 * - [ VC: IDREF ]
4049 * - [ VC: Entity Name ]
4050 * - [ VC: Notation Attributes ]
4051 *
4052 * The ID/IDREF uniqueness and matching are done separately
4053 *
4054 * returns 1 if valid or 0 otherwise
4055 */
4056
4057int
4058xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004059 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4060{
Owen Taylor3473f882001-02-23 17:55:21 +00004061 xmlAttributePtr attrDecl = NULL;
4062 int val;
4063 int ret = 1;
4064
4065 CHECK_DTD;
4066 if ((elem == NULL) || (elem->name == NULL)) return(0);
4067 if ((attr == NULL) || (attr->name == NULL)) return(0);
4068
4069 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004070 xmlChar fn[50];
4071 xmlChar *fullname;
4072
4073 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4074 if (fullname == NULL)
4075 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004076 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004077 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004078 attr->name, attr->ns->prefix);
4079 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004080 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004081 attr->name, attr->ns->prefix);
4082 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004083 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004084 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4085 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004086 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004087 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004088 if ((fullname != fn) && (fullname != elem->name))
4089 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004090 }
4091 if (attrDecl == NULL) {
4092 if (attr->ns != NULL) {
4093 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4094 attr->name, attr->ns->prefix);
4095 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4096 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4097 attr->name, attr->ns->prefix);
4098 } else {
4099 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4100 elem->name, attr->name);
4101 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4102 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4103 elem->name, attr->name);
4104 }
4105 }
4106
4107
4108 /* Validity Constraint: Attribute Value Type */
4109 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004110 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004111 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004112 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004113 return(0);
4114 }
4115 attr->atype = attrDecl->atype;
4116
4117 val = xmlValidateAttributeValue(attrDecl->atype, value);
4118 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004119 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004120 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004121 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004122 ret = 0;
4123 }
4124
4125 /* Validity constraint: Fixed Attribute Default */
4126 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4127 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004128 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004129 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004130 attr->name, elem->name, attrDecl->defaultValue);
4131 ret = 0;
4132 }
4133 }
4134
4135 /* Validity Constraint: ID uniqueness */
4136 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4137 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4138 ret = 0;
4139 }
4140
4141 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4142 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4143 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4144 ret = 0;
4145 }
4146
4147 /* Validity Constraint: Notation Attributes */
4148 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4149 xmlEnumerationPtr tree = attrDecl->tree;
4150 xmlNotationPtr nota;
4151
4152 /* First check that the given NOTATION was declared */
4153 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4154 if (nota == NULL)
4155 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4156
4157 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004158 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004159 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004160 value, attr->name, elem->name);
4161 ret = 0;
4162 }
4163
4164 /* Second, verify that it's among the list */
4165 while (tree != NULL) {
4166 if (xmlStrEqual(tree->name, value)) break;
4167 tree = tree->next;
4168 }
4169 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004170 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004171"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004172 value, attr->name, elem->name);
4173 ret = 0;
4174 }
4175 }
4176
4177 /* Validity Constraint: Enumeration */
4178 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4179 xmlEnumerationPtr tree = attrDecl->tree;
4180 while (tree != NULL) {
4181 if (xmlStrEqual(tree->name, value)) break;
4182 tree = tree->next;
4183 }
4184 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004185 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004186 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004187 value, attr->name, elem->name);
4188 ret = 0;
4189 }
4190 }
4191
4192 /* Fixed Attribute Default */
4193 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4194 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004195 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004196 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004197 attr->name, elem->name, attrDecl->defaultValue);
4198 ret = 0;
4199 }
4200
4201 /* Extra check for the attribute value */
4202 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4203 attrDecl->atype, value);
4204
4205 return(ret);
4206}
4207
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004208/**
4209 * xmlValidateOneNamespace:
4210 * @ctxt: the validation context
4211 * @doc: a document instance
4212 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004213 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004214 * @ns: an namespace declaration instance
4215 * @value: the attribute value (without entities processing)
4216 *
4217 * Try to validate a single namespace declaration for an element
4218 * basically it does the following checks as described by the
4219 * XML-1.0 recommendation:
4220 * - [ VC: Attribute Value Type ]
4221 * - [ VC: Fixed Attribute Default ]
4222 * - [ VC: Entity Name ]
4223 * - [ VC: Name Token ]
4224 * - [ VC: ID ]
4225 * - [ VC: IDREF ]
4226 * - [ VC: Entity Name ]
4227 * - [ VC: Notation Attributes ]
4228 *
4229 * The ID/IDREF uniqueness and matching are done separately
4230 *
4231 * returns 1 if valid or 0 otherwise
4232 */
4233
4234int
4235xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4236xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4237 /* xmlElementPtr elemDecl; */
4238 xmlAttributePtr attrDecl = NULL;
4239 int val;
4240 int ret = 1;
4241
4242 CHECK_DTD;
4243 if ((elem == NULL) || (elem->name == NULL)) return(0);
4244 if ((ns == NULL) || (ns->href == NULL)) return(0);
4245
4246 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004247 xmlChar fn[50];
4248 xmlChar *fullname;
4249
4250 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4251 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004252 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004253 return(0);
4254 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004255 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004256 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004257 ns->prefix, BAD_CAST "xmlns");
4258 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004259 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004260 ns->prefix, BAD_CAST "xmlns");
4261 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004262 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004263 BAD_CAST "xmlns");
4264 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004265 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004266 BAD_CAST "xmlns");
4267 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004268 if ((fullname != fn) && (fullname != elem->name))
4269 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004270 }
4271 if (attrDecl == NULL) {
4272 if (ns->prefix != NULL) {
4273 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4274 ns->prefix, BAD_CAST "xmlns");
4275 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4276 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4277 ns->prefix, BAD_CAST "xmlns");
4278 } else {
4279 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4280 elem->name, BAD_CAST "xmlns");
4281 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4282 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4283 elem->name, BAD_CAST "xmlns");
4284 }
4285 }
4286
4287
4288 /* Validity Constraint: Attribute Value Type */
4289 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004290 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004291 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004292 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004293 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004294 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004295 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004296 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004297 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004298 }
4299 return(0);
4300 }
4301
4302 val = xmlValidateAttributeValue(attrDecl->atype, value);
4303 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004304 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004305 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004306 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004307 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004308 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004309 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004310 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004311 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004312 }
4313 ret = 0;
4314 }
4315
4316 /* Validity constraint: Fixed Attribute Default */
4317 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4318 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004319 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004320 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004321 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4322 ns->prefix, elem->name, attrDecl->defaultValue);
4323 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004324 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004325 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004326 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004327 }
4328 ret = 0;
4329 }
4330 }
4331
4332 /* Validity Constraint: ID uniqueness */
4333 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4334 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4335 ret = 0;
4336 }
4337
4338 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4339 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4340 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4341 ret = 0;
4342 }
4343
4344 /* Validity Constraint: Notation Attributes */
4345 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4346 xmlEnumerationPtr tree = attrDecl->tree;
4347 xmlNotationPtr nota;
4348
4349 /* First check that the given NOTATION was declared */
4350 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4351 if (nota == NULL)
4352 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4353
4354 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004355 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004356 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004357 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4358 value, ns->prefix, elem->name);
4359 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004360 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004361 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004362 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004363 }
4364 ret = 0;
4365 }
4366
4367 /* Second, verify that it's among the list */
4368 while (tree != NULL) {
4369 if (xmlStrEqual(tree->name, value)) break;
4370 tree = tree->next;
4371 }
4372 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004373 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004374 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004375"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4376 value, ns->prefix, elem->name);
4377 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004378 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004379"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004380 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004381 }
4382 ret = 0;
4383 }
4384 }
4385
4386 /* Validity Constraint: Enumeration */
4387 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4388 xmlEnumerationPtr tree = attrDecl->tree;
4389 while (tree != NULL) {
4390 if (xmlStrEqual(tree->name, value)) break;
4391 tree = tree->next;
4392 }
4393 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004394 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004395 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004396"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4397 value, ns->prefix, elem->name);
4398 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004399 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004400"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004401 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004402 }
4403 ret = 0;
4404 }
4405 }
4406
4407 /* Fixed Attribute Default */
4408 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4409 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004410 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004411 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004412 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4413 ns->prefix, elem->name, attrDecl->defaultValue);
4414 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004415 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004416 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004417 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004418 }
4419 ret = 0;
4420 }
4421
4422 /* Extra check for the attribute value */
4423 if (ns->prefix != NULL) {
4424 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4425 attrDecl->atype, value);
4426 } else {
4427 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4428 attrDecl->atype, value);
4429 }
4430
4431 return(ret);
4432}
4433
Daniel Veillard118aed72002-09-24 14:13:13 +00004434#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004435/**
4436 * xmlValidateSkipIgnorable:
4437 * @ctxt: the validation context
4438 * @child: the child list
4439 *
4440 * Skip ignorable elements w.r.t. the validation process
4441 *
4442 * returns the first element to consider for validation of the content model
4443 */
4444
4445static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004446xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004447 while (child != NULL) {
4448 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004449 /* These things are ignored (skipped) during validation. */
4450 case XML_PI_NODE:
4451 case XML_COMMENT_NODE:
4452 case XML_XINCLUDE_START:
4453 case XML_XINCLUDE_END:
4454 child = child->next;
4455 break;
4456 case XML_TEXT_NODE:
4457 if (xmlIsBlankNode(child))
4458 child = child->next;
4459 else
4460 return(child);
4461 break;
4462 /* keep current node */
4463 default:
4464 return(child);
4465 }
4466 }
4467 return(child);
4468}
4469
4470/**
4471 * xmlValidateElementType:
4472 * @ctxt: the validation context
4473 *
4474 * Try to validate the content model of an element internal function
4475 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004476 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4477 * reference is found and -3 if the validation succeeded but
4478 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004479 */
4480
4481static int
4482xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004483 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004484 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004485
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004486 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004487 if ((NODE == NULL) && (CONT == NULL))
4488 return(1);
4489 if ((NODE == NULL) &&
4490 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4491 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4492 return(1);
4493 }
4494 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004495 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004496 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004497
4498 /*
4499 * We arrive here when more states need to be examined
4500 */
4501cont:
4502
4503 /*
4504 * We just recovered from a rollback generated by a possible
4505 * epsilon transition, go directly to the analysis phase
4506 */
4507 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004508 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004509 DEBUG_VALID_STATE(NODE, CONT)
4510 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004511 goto analyze;
4512 }
4513
4514 DEBUG_VALID_STATE(NODE, CONT)
4515 /*
4516 * we may have to save a backup state here. This is the equivalent
4517 * of handling epsilon transition in NFAs.
4518 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004519 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004520 ((CONT->parent == NULL) ||
4521 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004522 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004523 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004524 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004525 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004526 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4527 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004528 }
4529
4530
4531 /*
4532 * Check first if the content matches
4533 */
4534 switch (CONT->type) {
4535 case XML_ELEMENT_CONTENT_PCDATA:
4536 if (NODE == NULL) {
4537 DEBUG_VALID_MSG("pcdata failed no node");
4538 ret = 0;
4539 break;
4540 }
4541 if (NODE->type == XML_TEXT_NODE) {
4542 DEBUG_VALID_MSG("pcdata found, skip to next");
4543 /*
4544 * go to next element in the content model
4545 * skipping ignorable elems
4546 */
4547 do {
4548 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004549 NODE = xmlValidateSkipIgnorable(NODE);
4550 if ((NODE != NULL) &&
4551 (NODE->type == XML_ENTITY_REF_NODE))
4552 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004553 } while ((NODE != NULL) &&
4554 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004555 (NODE->type != XML_TEXT_NODE) &&
4556 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004557 ret = 1;
4558 break;
4559 } else {
4560 DEBUG_VALID_MSG("pcdata failed");
4561 ret = 0;
4562 break;
4563 }
4564 break;
4565 case XML_ELEMENT_CONTENT_ELEMENT:
4566 if (NODE == NULL) {
4567 DEBUG_VALID_MSG("element failed no node");
4568 ret = 0;
4569 break;
4570 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004571 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4572 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004573 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004574 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4575 ret = (CONT->prefix == NULL);
4576 } else if (CONT->prefix == NULL) {
4577 ret = 0;
4578 } else {
4579 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4580 }
4581 }
4582 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004583 DEBUG_VALID_MSG("element found, skip to next");
4584 /*
4585 * go to next element in the content model
4586 * skipping ignorable elems
4587 */
4588 do {
4589 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004590 NODE = xmlValidateSkipIgnorable(NODE);
4591 if ((NODE != NULL) &&
4592 (NODE->type == XML_ENTITY_REF_NODE))
4593 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004594 } while ((NODE != NULL) &&
4595 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004596 (NODE->type != XML_TEXT_NODE) &&
4597 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004598 } else {
4599 DEBUG_VALID_MSG("element failed");
4600 ret = 0;
4601 break;
4602 }
4603 break;
4604 case XML_ELEMENT_CONTENT_OR:
4605 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004606 * Small optimization.
4607 */
4608 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4609 if ((NODE == NULL) ||
4610 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4611 DEPTH++;
4612 CONT = CONT->c2;
4613 goto cont;
4614 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004615 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4616 ret = (CONT->c1->prefix == NULL);
4617 } else if (CONT->c1->prefix == NULL) {
4618 ret = 0;
4619 } else {
4620 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4621 }
4622 if (ret == 0) {
4623 DEPTH++;
4624 CONT = CONT->c2;
4625 goto cont;
4626 }
Daniel Veillard85349052001-04-20 13:48:21 +00004627 }
4628
4629 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004630 * save the second branch 'or' branch
4631 */
4632 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004633 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4634 OCCURS, ROLLBACK_OR) < 0)
4635 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004636 DEPTH++;
4637 CONT = CONT->c1;
4638 goto cont;
4639 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004640 /*
4641 * Small optimization.
4642 */
4643 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4644 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4645 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4646 if ((NODE == NULL) ||
4647 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4648 DEPTH++;
4649 CONT = CONT->c2;
4650 goto cont;
4651 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004652 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4653 ret = (CONT->c1->prefix == NULL);
4654 } else if (CONT->c1->prefix == NULL) {
4655 ret = 0;
4656 } else {
4657 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4658 }
4659 if (ret == 0) {
4660 DEPTH++;
4661 CONT = CONT->c2;
4662 goto cont;
4663 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004664 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004665 DEPTH++;
4666 CONT = CONT->c1;
4667 goto cont;
4668 }
4669
4670 /*
4671 * At this point handle going up in the tree
4672 */
4673 if (ret == -1) {
4674 DEBUG_VALID_MSG("error found returning");
4675 return(ret);
4676 }
4677analyze:
4678 while (CONT != NULL) {
4679 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004680 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004681 * this level.
4682 */
4683 if (ret == 0) {
4684 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004685 xmlNodePtr cur;
4686
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004687 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004688 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004689 DEBUG_VALID_MSG("Once branch failed, rollback");
4690 if (vstateVPop(ctxt) < 0 ) {
4691 DEBUG_VALID_MSG("exhaustion, failed");
4692 return(0);
4693 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004694 if (cur != ctxt->vstate->node)
4695 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004696 goto cont;
4697 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004698 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004699 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004700 DEBUG_VALID_MSG("Plus branch failed, rollback");
4701 if (vstateVPop(ctxt) < 0 ) {
4702 DEBUG_VALID_MSG("exhaustion, failed");
4703 return(0);
4704 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004705 if (cur != ctxt->vstate->node)
4706 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004707 goto cont;
4708 }
4709 DEBUG_VALID_MSG("Plus branch found");
4710 ret = 1;
4711 break;
4712 case XML_ELEMENT_CONTENT_MULT:
4713#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004714 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004715 DEBUG_VALID_MSG("Mult branch failed");
4716 } else {
4717 DEBUG_VALID_MSG("Mult branch found");
4718 }
4719#endif
4720 ret = 1;
4721 break;
4722 case XML_ELEMENT_CONTENT_OPT:
4723 DEBUG_VALID_MSG("Option branch failed");
4724 ret = 1;
4725 break;
4726 }
4727 } else {
4728 switch (CONT->ocur) {
4729 case XML_ELEMENT_CONTENT_OPT:
4730 DEBUG_VALID_MSG("Option branch succeeded");
4731 ret = 1;
4732 break;
4733 case XML_ELEMENT_CONTENT_ONCE:
4734 DEBUG_VALID_MSG("Once branch succeeded");
4735 ret = 1;
4736 break;
4737 case XML_ELEMENT_CONTENT_PLUS:
4738 if (STATE == ROLLBACK_PARENT) {
4739 DEBUG_VALID_MSG("Plus branch rollback");
4740 ret = 1;
4741 break;
4742 }
4743 if (NODE == NULL) {
4744 DEBUG_VALID_MSG("Plus branch exhausted");
4745 ret = 1;
4746 break;
4747 }
4748 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004749 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004750 goto cont;
4751 case XML_ELEMENT_CONTENT_MULT:
4752 if (STATE == ROLLBACK_PARENT) {
4753 DEBUG_VALID_MSG("Mult branch rollback");
4754 ret = 1;
4755 break;
4756 }
4757 if (NODE == NULL) {
4758 DEBUG_VALID_MSG("Mult branch exhausted");
4759 ret = 1;
4760 break;
4761 }
4762 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004763 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004764 goto cont;
4765 }
4766 }
4767 STATE = 0;
4768
4769 /*
4770 * Then act accordingly at the parent level
4771 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004772 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004773 if (CONT->parent == NULL)
4774 break;
4775
4776 switch (CONT->parent->type) {
4777 case XML_ELEMENT_CONTENT_PCDATA:
4778 DEBUG_VALID_MSG("Error: parent pcdata");
4779 return(-1);
4780 case XML_ELEMENT_CONTENT_ELEMENT:
4781 DEBUG_VALID_MSG("Error: parent element");
4782 return(-1);
4783 case XML_ELEMENT_CONTENT_OR:
4784 if (ret == 1) {
4785 DEBUG_VALID_MSG("Or succeeded");
4786 CONT = CONT->parent;
4787 DEPTH--;
4788 } else {
4789 DEBUG_VALID_MSG("Or failed");
4790 CONT = CONT->parent;
4791 DEPTH--;
4792 }
4793 break;
4794 case XML_ELEMENT_CONTENT_SEQ:
4795 if (ret == 0) {
4796 DEBUG_VALID_MSG("Sequence failed");
4797 CONT = CONT->parent;
4798 DEPTH--;
4799 } else if (CONT == CONT->parent->c1) {
4800 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4801 CONT = CONT->parent->c2;
4802 goto cont;
4803 } else {
4804 DEBUG_VALID_MSG("Sequence succeeded");
4805 CONT = CONT->parent;
4806 DEPTH--;
4807 }
4808 }
4809 }
4810 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004811 xmlNodePtr cur;
4812
4813 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004814 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4815 if (vstateVPop(ctxt) < 0 ) {
4816 DEBUG_VALID_MSG("exhaustion, failed");
4817 return(0);
4818 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004819 if (cur != ctxt->vstate->node)
4820 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004821 goto cont;
4822 }
4823 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004824 xmlNodePtr cur;
4825
4826 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004827 DEBUG_VALID_MSG("Failure, rollback");
4828 if (vstateVPop(ctxt) < 0 ) {
4829 DEBUG_VALID_MSG("exhaustion, failed");
4830 return(0);
4831 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004832 if (cur != ctxt->vstate->node)
4833 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004834 goto cont;
4835 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004836 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004837}
Daniel Veillard23e73572002-09-19 19:56:43 +00004838#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004839
4840/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00004841 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004842 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00004843 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004844 * @content: An element
4845 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4846 *
4847 * This will dump the list of elements to the buffer
4848 * Intended just for the debug routine
4849 */
4850static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00004851xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004852 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00004853 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004854
4855 if (node == NULL) return;
4856 if (glob) strcat(buf, "(");
4857 cur = node;
4858 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004859 len = strlen(buf);
4860 if (size - len < 50) {
4861 if ((size - len > 4) && (buf[len - 1] != '.'))
4862 strcat(buf, " ...");
4863 return;
4864 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004865 switch (cur->type) {
4866 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004867 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004868 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004869 if ((size - len > 4) && (buf[len - 1] != '.'))
4870 strcat(buf, " ...");
4871 return;
4872 }
4873 strcat(buf, (char *) cur->ns->prefix);
4874 strcat(buf, ":");
4875 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004876 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004877 if ((size - len > 4) && (buf[len - 1] != '.'))
4878 strcat(buf, " ...");
4879 return;
4880 }
4881 strcat(buf, (char *) cur->name);
4882 if (cur->next != NULL)
4883 strcat(buf, " ");
4884 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004885 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004886 if (xmlIsBlankNode(cur))
4887 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004888 case XML_CDATA_SECTION_NODE:
4889 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004890 strcat(buf, "CDATA");
4891 if (cur->next != NULL)
4892 strcat(buf, " ");
4893 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004894 case XML_ATTRIBUTE_NODE:
4895 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004896#ifdef LIBXML_DOCB_ENABLED
4897 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004898#endif
4899 case XML_HTML_DOCUMENT_NODE:
4900 case XML_DOCUMENT_TYPE_NODE:
4901 case XML_DOCUMENT_FRAG_NODE:
4902 case XML_NOTATION_NODE:
4903 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004904 strcat(buf, "???");
4905 if (cur->next != NULL)
4906 strcat(buf, " ");
4907 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004908 case XML_ENTITY_NODE:
4909 case XML_PI_NODE:
4910 case XML_DTD_NODE:
4911 case XML_COMMENT_NODE:
4912 case XML_ELEMENT_DECL:
4913 case XML_ATTRIBUTE_DECL:
4914 case XML_ENTITY_DECL:
4915 case XML_XINCLUDE_START:
4916 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004917 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004918 }
4919 cur = cur->next;
4920 }
4921 if (glob) strcat(buf, ")");
4922}
4923
4924/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004925 * xmlValidateElementContent:
4926 * @ctxt: the validation context
4927 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004928 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004929 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004930 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004931 *
4932 * Try to validate the content model of an element
4933 *
4934 * returns 1 if valid or 0 if not and -1 in case of error
4935 */
4936
4937static int
4938xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004939 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004940 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00004941#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00004942 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00004943#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00004944 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004945 xmlElementContentPtr cont;
4946 const xmlChar *name;
4947
4948 if (elemDecl == NULL)
4949 return(-1);
4950 cont = elemDecl->content;
4951 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004952
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004953#ifdef LIBXML_REGEXP_ENABLED
4954 /* Build the regexp associated to the content model */
4955 if (elemDecl->contModel == NULL)
4956 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4957 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004958 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004959 } else {
4960 xmlRegExecCtxtPtr exec;
4961
Daniel Veillardec498e12003-02-05 11:01:50 +00004962 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
4963 return(-1);
4964 }
Daniel Veillard01992e02002-10-09 10:20:30 +00004965 ctxt->nodeMax = 0;
4966 ctxt->nodeNr = 0;
4967 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004968 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4969 if (exec != NULL) {
4970 cur = child;
4971 while (cur != NULL) {
4972 switch (cur->type) {
4973 case XML_ENTITY_REF_NODE:
4974 /*
4975 * Push the current node to be able to roll back
4976 * and process within the entity
4977 */
4978 if ((cur->children != NULL) &&
4979 (cur->children->children != NULL)) {
4980 nodeVPush(ctxt, cur);
4981 cur = cur->children->children;
4982 continue;
4983 }
4984 break;
4985 case XML_TEXT_NODE:
4986 if (xmlIsBlankNode(cur))
4987 break;
4988 ret = 0;
4989 goto fail;
4990 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00004991 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004992 ret = 0;
4993 goto fail;
4994 case XML_ELEMENT_NODE:
4995 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004996 xmlChar fn[50];
4997 xmlChar *fullname;
4998
4999 fullname = xmlBuildQName(cur->name,
5000 cur->ns->prefix, fn, 50);
5001 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005002 ret = -1;
5003 goto fail;
5004 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005005 ret = xmlRegExecPushString(exec, fullname, NULL);
5006 if ((fullname != fn) && (fullname != cur->name))
5007 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005008 } else {
5009 ret = xmlRegExecPushString(exec, cur->name, NULL);
5010 }
5011 break;
5012 default:
5013 break;
5014 }
5015 /*
5016 * Switch to next element
5017 */
5018 cur = cur->next;
5019 while (cur == NULL) {
5020 cur = nodeVPop(ctxt);
5021 if (cur == NULL)
5022 break;
5023 cur = cur->next;
5024 }
5025 }
5026 ret = xmlRegExecPushString(exec, NULL, NULL);
5027fail:
5028 xmlRegFreeExecCtxt(exec);
5029 }
5030 }
5031#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005032 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005033 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005034 */
5035 ctxt->vstateMax = 8;
5036 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5037 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5038 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005039 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005040 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005041 }
5042 /*
5043 * The first entry in the stack is reserved to the current state
5044 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005045 ctxt->nodeMax = 0;
5046 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005047 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005048 ctxt->vstate = &ctxt->vstateTab[0];
5049 ctxt->vstateNr = 1;
5050 CONT = cont;
5051 NODE = child;
5052 DEPTH = 0;
5053 OCCURS = 0;
5054 STATE = 0;
5055 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005056 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005057 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5058 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005059 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005060 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005061 /*
5062 * An entities reference appeared at this level.
5063 * Buid a minimal representation of this node content
5064 * sufficient to run the validation process on it
5065 */
5066 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005067 cur = child;
5068 while (cur != NULL) {
5069 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005070 case XML_ENTITY_REF_NODE:
5071 /*
5072 * Push the current node to be able to roll back
5073 * and process within the entity
5074 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005075 if ((cur->children != NULL) &&
5076 (cur->children->children != NULL)) {
5077 nodeVPush(ctxt, cur);
5078 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005079 continue;
5080 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005081 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005082 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005083 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005084 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005085 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005086 case XML_CDATA_SECTION_NODE:
5087 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005088 case XML_ELEMENT_NODE:
5089 /*
5090 * Allocate a new node and minimally fills in
5091 * what's required
5092 */
5093 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5094 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005095 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005096 xmlFreeNodeList(repl);
5097 ret = -1;
5098 goto done;
5099 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005100 tmp->type = cur->type;
5101 tmp->name = cur->name;
5102 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005103 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005104 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005105 if (repl == NULL)
5106 repl = last = tmp;
5107 else {
5108 last->next = tmp;
5109 last = tmp;
5110 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005111 if (cur->type == XML_CDATA_SECTION_NODE) {
5112 /*
5113 * E59 spaces in CDATA does not match the
5114 * nonterminal S
5115 */
5116 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5117 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005118 break;
5119 default:
5120 break;
5121 }
5122 /*
5123 * Switch to next element
5124 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005125 cur = cur->next;
5126 while (cur == NULL) {
5127 cur = nodeVPop(ctxt);
5128 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005129 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005130 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005131 }
5132 }
5133
5134 /*
5135 * Relaunch the validation
5136 */
5137 ctxt->vstate = &ctxt->vstateTab[0];
5138 ctxt->vstateNr = 1;
5139 CONT = cont;
5140 NODE = repl;
5141 DEPTH = 0;
5142 OCCURS = 0;
5143 STATE = 0;
5144 ret = xmlValidateElementType(ctxt);
5145 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005146#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005147 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005148 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5149 char expr[5000];
5150 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005151
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005152 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005153 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005154 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005155#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005156 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005157 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005158 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005159#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005160 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005161
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005162 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005163 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5164 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5165 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005166 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005167 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5168 "Element content does not follow the DTD, expecting %s, got %s\n",
5169 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005170 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005171 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005172 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005173 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005174 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005175 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005176 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005177 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5178 "Element content does not follow the DTD\n",
5179 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005180 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005181 }
5182 ret = 0;
5183 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005184 if (ret == -3)
5185 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005186
Daniel Veillard23e73572002-09-19 19:56:43 +00005187#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005188done:
5189 /*
5190 * Deallocate the copy if done, and free up the validation stack
5191 */
5192 while (repl != NULL) {
5193 tmp = repl->next;
5194 xmlFree(repl);
5195 repl = tmp;
5196 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005197 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005198 if (ctxt->vstateTab != NULL) {
5199 xmlFree(ctxt->vstateTab);
5200 ctxt->vstateTab = NULL;
5201 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005202#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005203 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005204 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005205 if (ctxt->nodeTab != NULL) {
5206 xmlFree(ctxt->nodeTab);
5207 ctxt->nodeTab = NULL;
5208 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005209 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005210
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005211}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005212
Owen Taylor3473f882001-02-23 17:55:21 +00005213/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005214 * xmlValidateCdataElement:
5215 * @ctxt: the validation context
5216 * @doc: a document instance
5217 * @elem: an element instance
5218 *
5219 * Check that an element follows #CDATA
5220 *
5221 * returns 1 if valid or 0 otherwise
5222 */
5223static int
5224xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5225 xmlNodePtr elem) {
5226 int ret = 1;
5227 xmlNodePtr cur, child;
5228
Daniel Veillardceb09b92002-10-04 11:46:37 +00005229 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005230 return(0);
5231
5232 child = elem->children;
5233
5234 cur = child;
5235 while (cur != NULL) {
5236 switch (cur->type) {
5237 case XML_ENTITY_REF_NODE:
5238 /*
5239 * Push the current node to be able to roll back
5240 * and process within the entity
5241 */
5242 if ((cur->children != NULL) &&
5243 (cur->children->children != NULL)) {
5244 nodeVPush(ctxt, cur);
5245 cur = cur->children->children;
5246 continue;
5247 }
5248 break;
5249 case XML_COMMENT_NODE:
5250 case XML_PI_NODE:
5251 case XML_TEXT_NODE:
5252 case XML_CDATA_SECTION_NODE:
5253 break;
5254 default:
5255 ret = 0;
5256 goto done;
5257 }
5258 /*
5259 * Switch to next element
5260 */
5261 cur = cur->next;
5262 while (cur == NULL) {
5263 cur = nodeVPop(ctxt);
5264 if (cur == NULL)
5265 break;
5266 cur = cur->next;
5267 }
5268 }
5269done:
5270 ctxt->nodeMax = 0;
5271 ctxt->nodeNr = 0;
5272 if (ctxt->nodeTab != NULL) {
5273 xmlFree(ctxt->nodeTab);
5274 ctxt->nodeTab = NULL;
5275 }
5276 return(ret);
5277}
5278
5279/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005280 * xmlValidateCheckMixed:
5281 * @ctxt: the validation context
5282 * @cont: the mixed content model
5283 * @qname: the qualified name as appearing in the serialization
5284 *
5285 * Check if the given node is part of the content model.
5286 *
5287 * Returns 1 if yes, 0 if no, -1 in case of error
5288 */
5289static int
William M. Brackedb65a72004-02-06 07:36:04 +00005290xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005291 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005292 const xmlChar *name;
5293 int plen;
5294 name = xmlSplitQName3(qname, &plen);
5295
5296 if (name == NULL) {
5297 while (cont != NULL) {
5298 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5299 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5300 return(1);
5301 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5302 (cont->c1 != NULL) &&
5303 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5304 if ((cont->c1->prefix == NULL) &&
5305 (xmlStrEqual(cont->c1->name, qname)))
5306 return(1);
5307 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5308 (cont->c1 == NULL) ||
5309 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005310 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5311 "Internal: MIXED struct corrupted\n",
5312 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005313 break;
5314 }
5315 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005316 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005317 } else {
5318 while (cont != NULL) {
5319 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5320 if ((cont->prefix != NULL) &&
5321 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5322 (xmlStrEqual(cont->name, name)))
5323 return(1);
5324 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5325 (cont->c1 != NULL) &&
5326 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5327 if ((cont->c1->prefix != NULL) &&
5328 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5329 (xmlStrEqual(cont->c1->name, name)))
5330 return(1);
5331 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5332 (cont->c1 == NULL) ||
5333 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005334 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5335 "Internal: MIXED struct corrupted\n",
5336 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005337 break;
5338 }
5339 cont = cont->c2;
5340 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005341 }
5342 return(0);
5343}
5344
5345/**
5346 * xmlValidGetElemDecl:
5347 * @ctxt: the validation context
5348 * @doc: a document instance
5349 * @elem: an element instance
5350 * @extsubset: pointer, (out) indicate if the declaration was found
5351 * in the external subset.
5352 *
5353 * Finds a declaration associated to an element in the document.
5354 *
5355 * returns the pointer to the declaration or NULL if not found.
5356 */
5357static xmlElementPtr
5358xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5359 xmlNodePtr elem, int *extsubset) {
5360 xmlElementPtr elemDecl = NULL;
5361 const xmlChar *prefix = NULL;
5362
5363 if ((elem == NULL) || (elem->name == NULL)) return(NULL);
5364 if (extsubset != NULL)
5365 *extsubset = 0;
5366
5367 /*
5368 * Fetch the declaration for the qualified name
5369 */
5370 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5371 prefix = elem->ns->prefix;
5372
5373 if (prefix != NULL) {
5374 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5375 elem->name, prefix);
5376 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5377 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5378 elem->name, prefix);
5379 if ((elemDecl != NULL) && (extsubset != NULL))
5380 *extsubset = 1;
5381 }
5382 }
5383
5384 /*
5385 * Fetch the declaration for the non qualified name
5386 * This is "non-strict" validation should be done on the
5387 * full QName but in that case being flexible makes sense.
5388 */
5389 if (elemDecl == NULL) {
5390 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5391 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5392 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5393 if ((elemDecl != NULL) && (extsubset != NULL))
5394 *extsubset = 1;
5395 }
5396 }
5397 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005398 xmlErrValidNode(ctxt, elem,
5399 XML_DTD_UNKNOWN_ELEM,
5400 "No declaration for element %s\n",
5401 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005402 }
5403 return(elemDecl);
5404}
5405
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005406#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005407/**
5408 * xmlValidatePushElement:
5409 * @ctxt: the validation context
5410 * @doc: a document instance
5411 * @elem: an element instance
5412 * @qname: the qualified name as appearing in the serialization
5413 *
5414 * Push a new element start on the validation stack.
5415 *
5416 * returns 1 if no validation problem was found or 0 otherwise
5417 */
5418int
5419xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5420 xmlNodePtr elem, const xmlChar *qname) {
5421 int ret = 1;
5422 xmlElementPtr eDecl;
5423 int extsubset = 0;
5424
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005425/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005426 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5427 xmlValidStatePtr state = ctxt->vstate;
5428 xmlElementPtr elemDecl;
5429
5430 /*
5431 * Check the new element agaisnt the content model of the new elem.
5432 */
5433 if (state->elemDecl != NULL) {
5434 elemDecl = state->elemDecl;
5435
5436 switch(elemDecl->etype) {
5437 case XML_ELEMENT_TYPE_UNDEFINED:
5438 ret = 0;
5439 break;
5440 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005441 xmlErrValidNode(ctxt, state->node,
5442 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005443 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005444 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005445 ret = 0;
5446 break;
5447 case XML_ELEMENT_TYPE_ANY:
5448 /* I don't think anything is required then */
5449 break;
5450 case XML_ELEMENT_TYPE_MIXED:
5451 /* simple case of declared as #PCDATA */
5452 if ((elemDecl->content != NULL) &&
5453 (elemDecl->content->type ==
5454 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005455 xmlErrValidNode(ctxt, state->node,
5456 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005457 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005458 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005459 ret = 0;
5460 } else {
5461 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5462 qname);
5463 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005464 xmlErrValidNode(ctxt, state->node,
5465 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005466 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005467 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005468 }
5469 }
5470 break;
5471 case XML_ELEMENT_TYPE_ELEMENT:
5472 /*
5473 * TODO:
5474 * VC: Standalone Document Declaration
5475 * - element types with element content, if white space
5476 * occurs directly within any instance of those types.
5477 */
5478 if (state->exec != NULL) {
5479 ret = xmlRegExecPushString(state->exec, qname, NULL);
5480 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005481 xmlErrValidNode(ctxt, state->node,
5482 XML_DTD_CONTENT_MODEL,
5483 "Element %s content does not follow the DTD, Misplaced %s\n",
5484 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005485 ret = 0;
5486 } else {
5487 ret = 1;
5488 }
5489 }
5490 break;
5491 }
5492 }
5493 }
5494 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5495 vstateVPush(ctxt, eDecl, elem);
5496 return(ret);
5497}
5498
5499/**
5500 * xmlValidatePushCData:
5501 * @ctxt: the validation context
5502 * @data: some character data read
5503 * @len: the lenght of the data
5504 *
5505 * check the CData parsed for validation in the current stack
5506 *
5507 * returns 1 if no validation problem was found or 0 otherwise
5508 */
5509int
5510xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5511 int ret = 1;
5512
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005513/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005514 if (len <= 0)
5515 return(ret);
5516 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5517 xmlValidStatePtr state = ctxt->vstate;
5518 xmlElementPtr elemDecl;
5519
5520 /*
5521 * Check the new element agaisnt the content model of the new elem.
5522 */
5523 if (state->elemDecl != NULL) {
5524 elemDecl = state->elemDecl;
5525
5526 switch(elemDecl->etype) {
5527 case XML_ELEMENT_TYPE_UNDEFINED:
5528 ret = 0;
5529 break;
5530 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005531 xmlErrValidNode(ctxt, state->node,
5532 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005533 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005534 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005535 ret = 0;
5536 break;
5537 case XML_ELEMENT_TYPE_ANY:
5538 break;
5539 case XML_ELEMENT_TYPE_MIXED:
5540 break;
5541 case XML_ELEMENT_TYPE_ELEMENT:
5542 if (len > 0) {
5543 int i;
5544
5545 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005546 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005547 xmlErrValidNode(ctxt, state->node,
5548 XML_DTD_CONTENT_MODEL,
5549 "Element %s content does not follow the DTD, Text not allowed\n",
5550 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005551 ret = 0;
5552 goto done;
5553 }
5554 }
5555 /*
5556 * TODO:
5557 * VC: Standalone Document Declaration
5558 * element types with element content, if white space
5559 * occurs directly within any instance of those types.
5560 */
5561 }
5562 break;
5563 }
5564 }
5565 }
5566done:
5567 return(ret);
5568}
5569
5570/**
5571 * xmlValidatePopElement:
5572 * @ctxt: the validation context
5573 * @doc: a document instance
5574 * @elem: an element instance
5575 * @qname: the qualified name as appearing in the serialization
5576 *
5577 * Pop the element end from the validation stack.
5578 *
5579 * returns 1 if no validation problem was found or 0 otherwise
5580 */
5581int
5582xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005583 xmlNodePtr elem ATTRIBUTE_UNUSED,
5584 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005585 int ret = 1;
5586
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005587/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005588 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5589 xmlValidStatePtr state = ctxt->vstate;
5590 xmlElementPtr elemDecl;
5591
5592 /*
5593 * Check the new element agaisnt the content model of the new elem.
5594 */
5595 if (state->elemDecl != NULL) {
5596 elemDecl = state->elemDecl;
5597
5598 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5599 if (state->exec != NULL) {
5600 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5601 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005602 xmlErrValidNode(ctxt, state->node,
5603 XML_DTD_CONTENT_MODEL,
5604 "Element %s content does not follow the DTD, Expecting more child\n",
5605 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005606 } else {
5607 /*
5608 * previous validation errors should not generate
5609 * a new one here
5610 */
5611 ret = 1;
5612 }
5613 }
5614 }
5615 }
5616 vstateVPop(ctxt);
5617 }
5618 return(ret);
5619}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005620#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005621
5622/**
Owen Taylor3473f882001-02-23 17:55:21 +00005623 * xmlValidateOneElement:
5624 * @ctxt: the validation context
5625 * @doc: a document instance
5626 * @elem: an element instance
5627 *
5628 * Try to validate a single element and it's attributes,
5629 * basically it does the following checks as described by the
5630 * XML-1.0 recommendation:
5631 * - [ VC: Element Valid ]
5632 * - [ VC: Required Attribute ]
5633 * Then call xmlValidateOneAttribute() for each attribute present.
5634 *
5635 * The ID/IDREF checkings are done separately
5636 *
5637 * returns 1 if valid or 0 otherwise
5638 */
5639
5640int
5641xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5642 xmlNodePtr elem) {
5643 xmlElementPtr elemDecl = NULL;
5644 xmlElementContentPtr cont;
5645 xmlAttributePtr attr;
5646 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005647 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005648 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005649 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005650
5651 CHECK_DTD;
5652
5653 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005654 switch (elem->type) {
5655 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005656 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5657 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005658 return(0);
5659 case XML_TEXT_NODE:
5660 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005661 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5662 "Text element has children !\n",
5663 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005664 return(0);
5665 }
5666 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005667 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5668 "Text element has attribute !\n",
5669 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005670 return(0);
5671 }
5672 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005673 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5674 "Text element has namespace !\n",
5675 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005676 return(0);
5677 }
5678 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005679 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5680 "Text element has namespace !\n",
5681 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005682 return(0);
5683 }
5684 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005685 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5686 "Text element has no content !\n",
5687 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005688 return(0);
5689 }
5690 return(1);
5691 case XML_XINCLUDE_START:
5692 case XML_XINCLUDE_END:
5693 return(1);
5694 case XML_CDATA_SECTION_NODE:
5695 case XML_ENTITY_REF_NODE:
5696 case XML_PI_NODE:
5697 case XML_COMMENT_NODE:
5698 return(1);
5699 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005700 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5701 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005702 return(0);
5703 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005704 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5705 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005706 return(0);
5707 case XML_DOCUMENT_NODE:
5708 case XML_DOCUMENT_TYPE_NODE:
5709 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005710 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5711 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005712 return(0);
5713 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005714 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5715 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005716 return(0);
5717 case XML_ELEMENT_NODE:
5718 break;
5719 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005720 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5721 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005722 return(0);
5723 }
Owen Taylor3473f882001-02-23 17:55:21 +00005724
5725 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005726 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005727 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005728 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5729 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005730 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005731
Daniel Veillardea7751d2002-12-20 00:16:24 +00005732 /*
5733 * If vstateNr is not zero that means continuous validation is
5734 * activated, do not try to check the content model at that level.
5735 */
5736 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005737 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005738 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005739 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005740 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5741 "No declaration for element %s\n",
5742 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005743 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005744 case XML_ELEMENT_TYPE_EMPTY:
5745 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005746 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005747 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005748 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005749 ret = 0;
5750 }
5751 break;
5752 case XML_ELEMENT_TYPE_ANY:
5753 /* I don't think anything is required then */
5754 break;
5755 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005756
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005757 /* simple case of declared as #PCDATA */
5758 if ((elemDecl->content != NULL) &&
5759 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5760 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5761 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005762 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005763 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005764 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005765 }
5766 break;
5767 }
Owen Taylor3473f882001-02-23 17:55:21 +00005768 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005769 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005770 while (child != NULL) {
5771 if (child->type == XML_ELEMENT_NODE) {
5772 name = child->name;
5773 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005774 xmlChar fn[50];
5775 xmlChar *fullname;
5776
5777 fullname = xmlBuildQName(child->name, child->ns->prefix,
5778 fn, 50);
5779 if (fullname == NULL)
5780 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005781 cont = elemDecl->content;
5782 while (cont != NULL) {
5783 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005784 if (xmlStrEqual(cont->name, fullname))
5785 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005786 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5787 (cont->c1 != NULL) &&
5788 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005789 if (xmlStrEqual(cont->c1->name, fullname))
5790 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005791 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5792 (cont->c1 == NULL) ||
5793 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005794 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5795 "Internal: MIXED struct corrupted\n",
5796 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005797 break;
5798 }
5799 cont = cont->c2;
5800 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005801 if ((fullname != fn) && (fullname != child->name))
5802 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005803 if (cont != NULL)
5804 goto child_ok;
5805 }
5806 cont = elemDecl->content;
5807 while (cont != NULL) {
5808 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5809 if (xmlStrEqual(cont->name, name)) break;
5810 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5811 (cont->c1 != NULL) &&
5812 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5813 if (xmlStrEqual(cont->c1->name, name)) break;
5814 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5815 (cont->c1 == NULL) ||
5816 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005817 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5818 "Internal: MIXED struct corrupted\n",
5819 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005820 break;
5821 }
5822 cont = cont->c2;
5823 }
5824 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005825 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00005826 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005827 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005828 ret = 0;
5829 }
5830 }
5831child_ok:
5832 child = child->next;
5833 }
5834 break;
5835 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005836 if ((doc->standalone == 1) && (extsubset == 1)) {
5837 /*
5838 * VC: Standalone Document Declaration
5839 * - element types with element content, if white space
5840 * occurs directly within any instance of those types.
5841 */
5842 child = elem->children;
5843 while (child != NULL) {
5844 if (child->type == XML_TEXT_NODE) {
5845 const xmlChar *content = child->content;
5846
William M. Brack76e95df2003-10-18 16:20:14 +00005847 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005848 content++;
5849 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005850 xmlErrValidNode(ctxt, elem,
5851 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005852"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005853 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005854 ret = 0;
5855 break;
5856 }
5857 }
5858 child =child->next;
5859 }
5860 }
Owen Taylor3473f882001-02-23 17:55:21 +00005861 child = elem->children;
5862 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005863 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005864 if (tmp <= 0)
5865 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005866 break;
5867 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005868 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00005869
5870 /* [ VC: Required Attribute ] */
5871 attr = elemDecl->attributes;
5872 while (attr != NULL) {
5873 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005874 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005875
Daniel Veillarde4301c82002-02-13 13:32:35 +00005876 if ((attr->prefix == NULL) &&
5877 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5878 xmlNsPtr ns;
5879
5880 ns = elem->nsDef;
5881 while (ns != NULL) {
5882 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005883 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005884 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00005885 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005886 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5887 xmlNsPtr ns;
5888
5889 ns = elem->nsDef;
5890 while (ns != NULL) {
5891 if (xmlStrEqual(attr->name, ns->prefix))
5892 goto found;
5893 ns = ns->next;
5894 }
5895 } else {
5896 xmlAttrPtr attrib;
5897
5898 attrib = elem->properties;
5899 while (attrib != NULL) {
5900 if (xmlStrEqual(attrib->name, attr->name)) {
5901 if (attr->prefix != NULL) {
5902 xmlNsPtr nameSpace = attrib->ns;
5903
5904 if (nameSpace == NULL)
5905 nameSpace = elem->ns;
5906 /*
5907 * qualified names handling is problematic, having a
5908 * different prefix should be possible but DTDs don't
5909 * allow to define the URI instead of the prefix :-(
5910 */
5911 if (nameSpace == NULL) {
5912 if (qualified < 0)
5913 qualified = 0;
5914 } else if (!xmlStrEqual(nameSpace->prefix,
5915 attr->prefix)) {
5916 if (qualified < 1)
5917 qualified = 1;
5918 } else
5919 goto found;
5920 } else {
5921 /*
5922 * We should allow applications to define namespaces
5923 * for their application even if the DTD doesn't
5924 * carry one, otherwise, basically we would always
5925 * break.
5926 */
5927 goto found;
5928 }
5929 }
5930 attrib = attrib->next;
5931 }
Owen Taylor3473f882001-02-23 17:55:21 +00005932 }
5933 if (qualified == -1) {
5934 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005935 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005936 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005937 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005938 ret = 0;
5939 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005940 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005941 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005942 elem->name, attr->prefix,attr->name);
5943 ret = 0;
5944 }
5945 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005946 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005947 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005948 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005949 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005950 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005951 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005952 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005953 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005954 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5955 /*
5956 * Special tests checking #FIXED namespace declarations
5957 * have the right value since this is not done as an
5958 * attribute checking
5959 */
5960 if ((attr->prefix == NULL) &&
5961 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5962 xmlNsPtr ns;
5963
5964 ns = elem->nsDef;
5965 while (ns != NULL) {
5966 if (ns->prefix == NULL) {
5967 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005968 xmlErrValidNode(ctxt, elem,
5969 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00005970 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005971 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005972 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005973 }
5974 goto found;
5975 }
5976 ns = ns->next;
5977 }
5978 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5979 xmlNsPtr ns;
5980
5981 ns = elem->nsDef;
5982 while (ns != NULL) {
5983 if (xmlStrEqual(attr->name, ns->prefix)) {
5984 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005985 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005986 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005987 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005988 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005989 }
5990 goto found;
5991 }
5992 ns = ns->next;
5993 }
5994 }
Owen Taylor3473f882001-02-23 17:55:21 +00005995 }
5996found:
5997 attr = attr->nexth;
5998 }
5999 return(ret);
6000}
6001
6002/**
6003 * xmlValidateRoot:
6004 * @ctxt: the validation context
6005 * @doc: a document instance
6006 *
6007 * Try to validate a the root element
6008 * basically it does the following check as described by the
6009 * XML-1.0 recommendation:
6010 * - [ VC: Root Element Type ]
6011 * it doesn't try to recurse or apply other check to the element
6012 *
6013 * returns 1 if valid or 0 otherwise
6014 */
6015
6016int
6017xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6018 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006019 int ret;
6020
Owen Taylor3473f882001-02-23 17:55:21 +00006021 if (doc == NULL) return(0);
6022
6023 root = xmlDocGetRootElement(doc);
6024 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006025 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6026 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006027 return(0);
6028 }
6029
6030 /*
6031 * When doing post validation against a separate DTD, those may
6032 * no internal subset has been generated
6033 */
6034 if ((doc->intSubset != NULL) &&
6035 (doc->intSubset->name != NULL)) {
6036 /*
6037 * Check first the document root against the NQName
6038 */
6039 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6040 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006041 xmlChar fn[50];
6042 xmlChar *fullname;
6043
6044 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6045 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006046 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006047 return(0);
6048 }
6049 ret = xmlStrEqual(doc->intSubset->name, fullname);
6050 if ((fullname != fn) && (fullname != root->name))
6051 xmlFree(fullname);
6052 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006053 goto name_ok;
6054 }
6055 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6056 (xmlStrEqual(root->name, BAD_CAST "html")))
6057 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006058 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6059 "root and DTD name do not match '%s' and '%s'\n",
6060 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006061 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006062 }
6063 }
6064name_ok:
6065 return(1);
6066}
6067
6068
6069/**
6070 * xmlValidateElement:
6071 * @ctxt: the validation context
6072 * @doc: a document instance
6073 * @elem: an element instance
6074 *
6075 * Try to validate the subtree under an element
6076 *
6077 * returns 1 if valid or 0 otherwise
6078 */
6079
6080int
6081xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6082 xmlNodePtr child;
6083 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006084 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006085 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006086 int ret = 1;
6087
6088 if (elem == NULL) return(0);
6089
6090 /*
6091 * XInclude elements were added after parsing in the infoset,
6092 * they don't really mean anything validation wise.
6093 */
6094 if ((elem->type == XML_XINCLUDE_START) ||
6095 (elem->type == XML_XINCLUDE_END))
6096 return(1);
6097
6098 CHECK_DTD;
6099
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006100 /*
6101 * Entities references have to be handled separately
6102 */
6103 if (elem->type == XML_ENTITY_REF_NODE) {
6104 return(1);
6105 }
6106
Owen Taylor3473f882001-02-23 17:55:21 +00006107 ret &= xmlValidateOneElement(ctxt, doc, elem);
6108 attr = elem->properties;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006109 while (attr != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006110 value = xmlNodeListGetString(doc, attr->children, 0);
6111 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6112 if (value != NULL)
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006113 xmlFree((char *)value);
Owen Taylor3473f882001-02-23 17:55:21 +00006114 attr= attr->next;
6115 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006116 ns = elem->nsDef;
6117 while (ns != NULL) {
Daniel Veillard1f5c9892003-12-29 17:09:55 +00006118 if (elem->ns == NULL)
6119 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6120 ns, ns->href);
6121 else
6122 ret &= xmlValidateOneNamespace(ctxt, doc, elem, elem->ns->prefix,
6123 ns, ns->href);
Daniel Veillarde133dd82003-10-30 10:42:20 +00006124 ns = ns->next;
6125 }
Owen Taylor3473f882001-02-23 17:55:21 +00006126 child = elem->children;
6127 while (child != NULL) {
6128 ret &= xmlValidateElement(ctxt, doc, child);
6129 child = child->next;
6130 }
6131
6132 return(ret);
6133}
6134
Daniel Veillard8730c562001-02-26 10:49:57 +00006135/**
6136 * xmlValidateRef:
6137 * @ref: A reference to be validated
6138 * @ctxt: Validation context
6139 * @name: Name of ID we are searching for
6140 *
6141 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006142static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006143xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006144 const xmlChar *name) {
6145 xmlAttrPtr id;
6146 xmlAttrPtr attr;
6147
6148 if (ref == NULL)
6149 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006150 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006151 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006152 attr = ref->attr;
6153 if (attr == NULL) {
6154 xmlChar *dup, *str = NULL, *cur, save;
6155
6156 dup = xmlStrdup(name);
6157 if (dup == NULL) {
6158 ctxt->valid = 0;
6159 return;
6160 }
6161 cur = dup;
6162 while (*cur != 0) {
6163 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006164 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006165 save = *cur;
6166 *cur = 0;
6167 id = xmlGetID(ctxt->doc, str);
6168 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006169 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006170 "attribute %s line %d references an unknown ID \"%s\"\n",
6171 ref->name, ref->lineno, str);
6172 ctxt->valid = 0;
6173 }
6174 if (save == 0)
6175 break;
6176 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006177 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006178 }
6179 xmlFree(dup);
6180 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006181 id = xmlGetID(ctxt->doc, name);
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 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006185 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006186 ctxt->valid = 0;
6187 }
6188 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6189 xmlChar *dup, *str = NULL, *cur, save;
6190
6191 dup = xmlStrdup(name);
6192 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006193 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006194 ctxt->valid = 0;
6195 return;
6196 }
6197 cur = dup;
6198 while (*cur != 0) {
6199 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006200 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006201 save = *cur;
6202 *cur = 0;
6203 id = xmlGetID(ctxt->doc, str);
6204 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006205 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006206 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006207 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006208 ctxt->valid = 0;
6209 }
6210 if (save == 0)
6211 break;
6212 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006213 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006214 }
6215 xmlFree(dup);
6216 }
6217}
6218
6219/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006220 * xmlWalkValidateList:
6221 * @data: Contents of current link
6222 * @user: Value supplied by the user
6223 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006224 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006225 */
6226static int
6227xmlWalkValidateList(const void *data, const void *user)
6228{
6229 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6230 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6231 return 1;
6232}
6233
6234/**
6235 * xmlValidateCheckRefCallback:
6236 * @ref_list: List of references
6237 * @ctxt: Validation context
6238 * @name: Name of ID we are searching for
6239 *
6240 */
6241static void
6242xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6243 const xmlChar *name) {
6244 xmlValidateMemo memo;
6245
6246 if (ref_list == NULL)
6247 return;
6248 memo.ctxt = ctxt;
6249 memo.name = name;
6250
6251 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6252
6253}
6254
6255/**
Owen Taylor3473f882001-02-23 17:55:21 +00006256 * xmlValidateDocumentFinal:
6257 * @ctxt: the validation context
6258 * @doc: a document instance
6259 *
6260 * Does the final step for the document validation once all the
6261 * incremental validation steps have been completed
6262 *
6263 * basically it does the following checks described by the XML Rec
6264 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006265 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006266 *
6267 * returns 1 if valid or 0 otherwise
6268 */
6269
6270int
6271xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6272 xmlRefTablePtr table;
6273
6274 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006275 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6276 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006277 return(0);
6278 }
6279
6280 /*
6281 * Check all the NOTATION/NOTATIONS attributes
6282 */
6283 /*
6284 * Check all the ENTITY/ENTITIES attributes definition for validity
6285 */
6286 /*
6287 * Check all the IDREF/IDREFS attributes definition for validity
6288 */
6289 table = (xmlRefTablePtr) doc->refs;
6290 ctxt->doc = doc;
6291 ctxt->valid = 1;
6292 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6293 return(ctxt->valid);
6294}
6295
6296/**
6297 * xmlValidateDtd:
6298 * @ctxt: the validation context
6299 * @doc: a document instance
6300 * @dtd: a dtd instance
6301 *
6302 * Try to validate the document against the dtd instance
6303 *
6304 * basically it does check all the definitions in the DtD.
6305 *
6306 * returns 1 if valid or 0 otherwise
6307 */
6308
6309int
6310xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6311 int ret;
6312 xmlDtdPtr oldExt;
6313 xmlNodePtr root;
6314
6315 if (dtd == NULL) return(0);
6316 if (doc == NULL) return(0);
6317 oldExt = doc->extSubset;
6318 doc->extSubset = dtd;
6319 ret = xmlValidateRoot(ctxt, doc);
6320 if (ret == 0) {
6321 doc->extSubset = oldExt;
6322 return(ret);
6323 }
6324 if (doc->ids != NULL) {
6325 xmlFreeIDTable(doc->ids);
6326 doc->ids = NULL;
6327 }
6328 if (doc->refs != NULL) {
6329 xmlFreeRefTable(doc->refs);
6330 doc->refs = NULL;
6331 }
6332 root = xmlDocGetRootElement(doc);
6333 ret = xmlValidateElement(ctxt, doc, root);
6334 ret &= xmlValidateDocumentFinal(ctxt, doc);
6335 doc->extSubset = oldExt;
6336 return(ret);
6337}
6338
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006339static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006340xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6341 const xmlChar *name ATTRIBUTE_UNUSED) {
6342 if (cur == NULL)
6343 return;
6344 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6345 xmlChar *notation = cur->content;
6346
Daniel Veillard878eab02002-02-19 13:46:09 +00006347 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006348 int ret;
6349
6350 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6351 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006352 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006353 }
6354 }
6355 }
6356}
6357
6358static void
Owen Taylor3473f882001-02-23 17:55:21 +00006359xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006360 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006361 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006362 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006363 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006364
Owen Taylor3473f882001-02-23 17:55:21 +00006365 if (cur == NULL)
6366 return;
6367 switch (cur->atype) {
6368 case XML_ATTRIBUTE_CDATA:
6369 case XML_ATTRIBUTE_ID:
6370 case XML_ATTRIBUTE_IDREF :
6371 case XML_ATTRIBUTE_IDREFS:
6372 case XML_ATTRIBUTE_NMTOKEN:
6373 case XML_ATTRIBUTE_NMTOKENS:
6374 case XML_ATTRIBUTE_ENUMERATION:
6375 break;
6376 case XML_ATTRIBUTE_ENTITY:
6377 case XML_ATTRIBUTE_ENTITIES:
6378 case XML_ATTRIBUTE_NOTATION:
6379 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006380
6381 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6382 cur->atype, cur->defaultValue);
6383 if ((ret == 0) && (ctxt->valid == 1))
6384 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006385 }
6386 if (cur->tree != NULL) {
6387 xmlEnumerationPtr tree = cur->tree;
6388 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006389 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006390 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006391 if ((ret == 0) && (ctxt->valid == 1))
6392 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006393 tree = tree->next;
6394 }
6395 }
6396 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006397 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6398 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006399 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006400 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006401 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006402 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006403 return;
6404 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006405
6406 if (doc != NULL)
6407 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6408 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006409 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006410 if ((elem == NULL) && (cur->parent != NULL) &&
6411 (cur->parent->type == XML_DTD_NODE))
6412 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006413 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006414 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006415 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006416 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006417 return;
6418 }
6419 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006420 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006421 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006422 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006423 ctxt->valid = 0;
6424 }
6425 }
Owen Taylor3473f882001-02-23 17:55:21 +00006426}
6427
6428/**
6429 * xmlValidateDtdFinal:
6430 * @ctxt: the validation context
6431 * @doc: a document instance
6432 *
6433 * Does the final step for the dtds validation once all the
6434 * subsets have been parsed
6435 *
6436 * basically it does the following checks described by the XML Rec
6437 * - check that ENTITY and ENTITIES type attributes default or
6438 * possible values matches one of the defined entities.
6439 * - check that NOTATION type attributes default or
6440 * possible values matches one of the defined notations.
6441 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006442 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006443 */
6444
6445int
6446xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006447 xmlDtdPtr dtd;
6448 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006449 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006450
6451 if (doc == NULL) return(0);
6452 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6453 return(0);
6454 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006455 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006456 dtd = doc->intSubset;
6457 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6458 table = (xmlAttributeTablePtr) dtd->attributes;
6459 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006460 }
6461 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006462 entities = (xmlEntitiesTablePtr) dtd->entities;
6463 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6464 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006465 }
6466 dtd = doc->extSubset;
6467 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6468 table = (xmlAttributeTablePtr) dtd->attributes;
6469 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006470 }
6471 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006472 entities = (xmlEntitiesTablePtr) dtd->entities;
6473 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6474 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006475 }
6476 return(ctxt->valid);
6477}
6478
6479/**
6480 * xmlValidateDocument:
6481 * @ctxt: the validation context
6482 * @doc: a document instance
6483 *
6484 * Try to validate the document instance
6485 *
6486 * basically it does the all the checks described by the XML Rec
6487 * i.e. validates the internal and external subset (if present)
6488 * and validate the document tree.
6489 *
6490 * returns 1 if valid or 0 otherwise
6491 */
6492
6493int
6494xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6495 int ret;
6496 xmlNodePtr root;
6497
Daniel Veillard2fd85422002-10-16 14:32:41 +00006498 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006499 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6500 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006501 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006502 }
Owen Taylor3473f882001-02-23 17:55:21 +00006503 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6504 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
William M. Brackbebe7302004-08-05 06:46:47 +00006505 xmlChar *extID, *sysID;
6506 if (doc->intSubset->ExternalID != NULL)
6507 extID = xmlBuildURI(doc->intSubset->ExternalID,
6508 doc->URL);
6509 else
6510 extID = NULL;
6511 if (doc->intSubset->SystemID != NULL)
6512 sysID = xmlBuildURI(doc->intSubset->SystemID,
6513 doc->URL);
6514 else
6515 sysID = NULL;
6516 doc->extSubset = xmlParseDTD((const xmlChar *)extID,
6517 (const xmlChar *)sysID);
6518 if (extID != NULL)
6519 xmlFree(extID);
6520 if (sysID != NULL)
6521 xmlFree(sysID);
Owen Taylor3473f882001-02-23 17:55:21 +00006522 if (doc->extSubset == NULL) {
6523 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006524 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006525 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006526 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006527 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006528 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006529 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006530 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006531 }
6532 return(0);
6533 }
6534 }
6535
6536 if (doc->ids != NULL) {
6537 xmlFreeIDTable(doc->ids);
6538 doc->ids = NULL;
6539 }
6540 if (doc->refs != NULL) {
6541 xmlFreeRefTable(doc->refs);
6542 doc->refs = NULL;
6543 }
6544 ret = xmlValidateDtdFinal(ctxt, doc);
6545 if (!xmlValidateRoot(ctxt, doc)) return(0);
6546
6547 root = xmlDocGetRootElement(doc);
6548 ret &= xmlValidateElement(ctxt, doc, root);
6549 ret &= xmlValidateDocumentFinal(ctxt, doc);
6550 return(ret);
6551}
6552
Owen Taylor3473f882001-02-23 17:55:21 +00006553/************************************************************************
6554 * *
6555 * Routines for dynamic validation editing *
6556 * *
6557 ************************************************************************/
6558
6559/**
6560 * xmlValidGetPotentialChildren:
6561 * @ctree: an element content tree
6562 * @list: an array to store the list of child names
6563 * @len: a pointer to the number of element in the list
6564 * @max: the size of the array
6565 *
6566 * Build/extend a list of potential children allowed by the content tree
6567 *
6568 * returns the number of element in the list, or -1 in case of error.
6569 */
6570
6571int
6572xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6573 int *len, int max) {
6574 int i;
6575
6576 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6577 return(-1);
6578 if (*len >= max) return(*len);
6579
6580 switch (ctree->type) {
6581 case XML_ELEMENT_CONTENT_PCDATA:
6582 for (i = 0; i < *len;i++)
6583 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6584 list[(*len)++] = BAD_CAST "#PCDATA";
6585 break;
6586 case XML_ELEMENT_CONTENT_ELEMENT:
6587 for (i = 0; i < *len;i++)
6588 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6589 list[(*len)++] = ctree->name;
6590 break;
6591 case XML_ELEMENT_CONTENT_SEQ:
6592 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6593 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6594 break;
6595 case XML_ELEMENT_CONTENT_OR:
6596 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6597 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6598 break;
6599 }
6600
6601 return(*len);
6602}
6603
William M. Brack9333cc22004-06-24 08:33:40 +00006604/*
6605 * Dummy function to suppress messages while we try out valid elements
6606 */
6607static void xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
6608 const char *msg ATTRIBUTE_UNUSED, ...) {
6609 return;
6610}
6611
Owen Taylor3473f882001-02-23 17:55:21 +00006612/**
6613 * xmlValidGetValidElements:
6614 * @prev: an element to insert after
6615 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006616 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006617 * @max: the size of the array
6618 *
6619 * This function returns the list of authorized children to insert
6620 * within an existing tree while respecting the validity constraints
6621 * forced by the Dtd. The insertion point is defined using @prev and
6622 * @next in the following ways:
6623 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6624 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6625 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6626 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6627 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6628 *
6629 * pointers to the element names are inserted at the beginning of the array
6630 * and do not need to be freed.
6631 *
6632 * returns the number of element in the list, or -1 in case of error. If
6633 * the function returns the value @max the caller is invited to grow the
6634 * receiving array and retry.
6635 */
6636
6637int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006638xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006639 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006640 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006641 int nb_valid_elements = 0;
6642 const xmlChar *elements[256];
6643 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006644 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006645
6646 xmlNode *ref_node;
6647 xmlNode *parent;
6648 xmlNode *test_node;
6649
6650 xmlNode *prev_next;
6651 xmlNode *next_prev;
6652 xmlNode *parent_childs;
6653 xmlNode *parent_last;
6654
6655 xmlElement *element_desc;
6656
6657 if (prev == NULL && next == NULL)
6658 return(-1);
6659
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006660 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006661 if (max <= 0) return(-1);
6662
William M. Brack9333cc22004-06-24 08:33:40 +00006663 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6664 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6665
Owen Taylor3473f882001-02-23 17:55:21 +00006666 nb_valid_elements = 0;
6667 ref_node = prev ? prev : next;
6668 parent = ref_node->parent;
6669
6670 /*
6671 * Retrieves the parent element declaration
6672 */
6673 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6674 parent->name);
6675 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6676 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6677 parent->name);
6678 if (element_desc == NULL) return(-1);
6679
6680 /*
6681 * Do a backup of the current tree structure
6682 */
6683 prev_next = prev ? prev->next : NULL;
6684 next_prev = next ? next->prev : NULL;
6685 parent_childs = parent->children;
6686 parent_last = parent->last;
6687
6688 /*
6689 * Creates a dummy node and insert it into the tree
6690 */
6691 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
6692 test_node->doc = ref_node->doc;
6693 test_node->parent = parent;
6694 test_node->prev = prev;
6695 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006696 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006697
6698 if (prev) prev->next = test_node;
6699 else parent->children = test_node;
6700
6701 if (next) next->prev = test_node;
6702 else parent->last = test_node;
6703
6704 /*
6705 * Insert each potential child node and check if the parent is
6706 * still valid
6707 */
6708 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6709 elements, &nb_elements, 256);
6710
6711 for (i = 0;i < nb_elements;i++) {
6712 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006713 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006714 int j;
6715
6716 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006717 if (xmlStrEqual(elements[i], names[j])) break;
6718 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00006719 if (nb_valid_elements >= max) break;
6720 }
6721 }
6722
6723 /*
6724 * Restore the tree structure
6725 */
6726 if (prev) prev->next = prev_next;
6727 if (next) next->prev = next_prev;
6728 parent->children = parent_childs;
6729 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006730
6731 /*
6732 * Free up the dummy node
6733 */
6734 test_node->name = name;
6735 xmlFreeNode(test_node);
6736
Owen Taylor3473f882001-02-23 17:55:21 +00006737 return(nb_valid_elements);
6738}
Daniel Veillard4432df22003-09-28 18:58:27 +00006739#endif /* LIBXML_VALID_ENABLED */
6740