blob: 0a2cedc829f3a9afe3869df21491f4e6bc74c204 [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 Veillardbb5abab2003-10-03 22:21:51 +000065 pctxt, NULL, XML_FROM_DTD, XML_ERR_NO_MEMORY,
66 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 Veillardbb5abab2003-10-03 22:21:51 +000070 pctxt, NULL, XML_FROM_DTD, XML_ERR_NO_MEMORY,
71 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
84xmlErrValid(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, 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 Veillardbb5abab2003-10-03 22:21:51 +000098 pctxt, NULL, XML_FROM_DTD, error,
99 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 Veillardbb5abab2003-10-03 22:21:51 +0000103 pctxt, NULL, XML_FROM_DTD, error,
104 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
105 msg);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000106}
107
Daniel Veillardd61e8fb2003-10-19 21:59:17 +0000108#ifdef LIBXML_VALID_ENABLED
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000109/**
110 * xmlErrValidNodeNr:
111 * @ctxt: an XML validation parser context
112 * @node: the node raising the error
113 * @error: the error number
114 * @str1: extra informations
115 * @int2: extra informations
116 * @str3: extra informations
117 *
118 * Handle a validation error, provide contextual informations
119 */
120static void
121xmlErrValidNodeNr(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
122 xmlNodePtr node, xmlParserErrors error,
123 const char *msg, const xmlChar * str1,
124 int int2, const xmlChar * str3)
125{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000126 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000127 xmlGenericErrorFunc channel = NULL;
128 xmlParserCtxtPtr pctxt = NULL;
129 void *data = NULL;
130
131 if (ctxt != NULL) {
132 channel = ctxt->error;
133 data = ctxt->userData;
134 pctxt = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000135 pctxt = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000136 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000137 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_DTD, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000138 XML_ERR_ERROR, NULL, 0,
139 (const char *) str1,
140 (const char *) str3,
141 NULL, int2, 0, msg, str1, int2, str3);
142}
143/**
144 * xmlErrValidNode:
145 * @ctxt: an XML validation parser context
146 * @node: the node raising the error
147 * @error: the error number
148 * @str1: extra informations
149 * @str2: extra informations
150 * @str3: extra informations
151 *
152 * Handle a validation error, provide contextual informations
153 */
154static void
155xmlErrValidNode(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
156 xmlNodePtr node, xmlParserErrors error,
157 const char *msg, const xmlChar * str1,
158 const xmlChar * str2, const xmlChar * str3)
159{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000160 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000161 xmlGenericErrorFunc channel = NULL;
162 xmlParserCtxtPtr pctxt = NULL;
163 void *data = NULL;
164
165 if (ctxt != NULL) {
166 channel = ctxt->error;
167 data = ctxt->userData;
168 pctxt = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000169 pctxt = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000170 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000171 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_DTD, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000172 XML_ERR_ERROR, NULL, 0,
173 (const char *) str1,
174 (const char *) str1,
175 (const char *) str3, 0, 0, msg, str1, str2, str3);
176}
177/**
178 * xmlErrValidWarning:
179 * @ctxt: an XML validation parser context
180 * @node: the node raising the error
181 * @error: the error number
182 * @str1: extra informations
183 * @str2: extra informations
184 * @str3: extra informations
185 *
186 * Handle a validation error, provide contextual informations
187 */
188static void
189xmlErrValidWarning(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
190 xmlNodePtr node, xmlParserErrors error,
191 const char *msg, const xmlChar * str1,
192 const xmlChar * str2, const xmlChar * str3)
193{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000194 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000195 xmlGenericErrorFunc channel = NULL;
196 xmlParserCtxtPtr pctxt = NULL;
197 void *data = NULL;
198
199 if (ctxt != NULL) {
200 channel = ctxt->error;
201 data = ctxt->userData;
202 pctxt = ctxt->userData;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000203 pctxt = ctxt->userData;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000204 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000205 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_DTD, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000206 XML_ERR_WARNING, NULL, 0,
207 (const char *) str1,
208 (const char *) str1,
209 (const char *) str3, 0, 0, msg, str1, str2, str3);
210}
211
212
Daniel Veillardea7751d2002-12-20 00:16:24 +0000213
214#ifdef LIBXML_REGEXP_ENABLED
215/*
216 * If regexp are enabled we can do continuous validation without the
217 * need of a tree to validate the content model. this is done in each
218 * callbacks.
219 * Each xmlValidState represent the validation state associated to the
220 * set of nodes currently open from the document root to the current element.
221 */
222
223
224typedef struct _xmlValidState {
225 xmlElementPtr elemDecl; /* pointer to the content model */
226 xmlNodePtr node; /* pointer to the current node */
227 xmlRegExecCtxtPtr exec; /* regexp runtime */
228} _xmlValidState;
229
230
231static int
232vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000233 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000234 ctxt->vstateMax = 10;
235 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
236 sizeof(ctxt->vstateTab[0]));
237 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000238 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000239 return(-1);
240 }
241 }
242
243 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000244 xmlValidState *tmp;
245
246 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
247 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
248 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000249 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000250 return(-1);
251 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000252 ctxt->vstateMax *= 2;
253 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000254 }
255 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
256 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
257 ctxt->vstateTab[ctxt->vstateNr].node = node;
258 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
259 if (elemDecl->contModel == NULL)
260 xmlValidBuildContentModel(ctxt, elemDecl);
261 if (elemDecl->contModel != NULL) {
262 ctxt->vstateTab[ctxt->vstateNr].exec =
263 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
264 } else {
265 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000266 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
267 XML_ERR_INTERNAL_ERROR,
268 "Failed to build content model regexp for %s\n",
269 node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000270 }
271 }
272 return(ctxt->vstateNr++);
273}
274
275static int
276vstateVPop(xmlValidCtxtPtr ctxt) {
277 xmlElementPtr elemDecl;
278
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000279 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000280 ctxt->vstateNr--;
281 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
282 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
283 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
284 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
285 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
286 }
287 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
288 if (ctxt->vstateNr >= 1)
289 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
290 else
291 ctxt->vstate = NULL;
292 return(ctxt->vstateNr);
293}
294
295#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000296/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000297 * If regexp are not enabled, it uses a home made algorithm less
298 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000299 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000300 * only restriction is on the deepness of the tree limited by the
301 * size of the occurs bitfield
302 *
303 * this is the content of a saved state for rollbacks
304 */
305
306#define ROLLBACK_OR 0
307#define ROLLBACK_PARENT 1
308
Daniel Veillardb44025c2001-10-11 22:55:55 +0000309typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000310 xmlElementContentPtr cont; /* pointer to the content model subtree */
311 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000312 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000313 unsigned char depth; /* current depth in the overall tree */
314 unsigned char state; /* ROLLBACK_XXX */
315} _xmlValidState;
316
Daniel Veillardfc57b412002-04-29 15:50:14 +0000317#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000318#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
319#define CONT ctxt->vstate->cont
320#define NODE ctxt->vstate->node
321#define DEPTH ctxt->vstate->depth
322#define OCCURS ctxt->vstate->occurs
323#define STATE ctxt->vstate->state
324
Daniel Veillard5344c602001-12-31 16:37:34 +0000325#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
326#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000327
Daniel Veillard5344c602001-12-31 16:37:34 +0000328#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
329#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000330
331static int
332vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
333 xmlNodePtr node, unsigned char depth, long occurs,
334 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000335 int i = ctxt->vstateNr - 1;
336
Daniel Veillard940492d2002-04-15 10:15:25 +0000337 if (ctxt->vstateNr > MAX_RECURSE) {
338 return(-1);
339 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000340 if (ctxt->vstateTab == NULL) {
341 ctxt->vstateMax = 8;
342 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
343 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
344 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000345 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000346 return(-1);
347 }
348 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000349 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000350 xmlValidState *tmp;
351
352 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
353 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
354 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000355 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000356 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000357 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000358 ctxt->vstateMax *= 2;
359 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000360 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000361 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000362 /*
363 * Don't push on the stack a state already here
364 */
365 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
366 (ctxt->vstateTab[i].node == node) &&
367 (ctxt->vstateTab[i].depth == depth) &&
368 (ctxt->vstateTab[i].occurs == occurs) &&
369 (ctxt->vstateTab[i].state == state))
370 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000371 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
372 ctxt->vstateTab[ctxt->vstateNr].node = node;
373 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
374 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
375 ctxt->vstateTab[ctxt->vstateNr].state = state;
376 return(ctxt->vstateNr++);
377}
378
379static int
380vstateVPop(xmlValidCtxtPtr ctxt) {
381 if (ctxt->vstateNr <= 1) return(-1);
382 ctxt->vstateNr--;
383 ctxt->vstate = &ctxt->vstateTab[0];
384 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
385 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
386 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
387 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
388 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
389 return(ctxt->vstateNr);
390}
391
Daniel Veillard118aed72002-09-24 14:13:13 +0000392#endif /* LIBXML_REGEXP_ENABLED */
393
Daniel Veillard1c732d22002-11-30 11:22:59 +0000394static int
395nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
396{
397 if (ctxt->nodeMax <= 0) {
398 ctxt->nodeMax = 4;
399 ctxt->nodeTab =
400 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
401 sizeof(ctxt->nodeTab[0]));
402 if (ctxt->nodeTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000403 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000404 ctxt->nodeMax = 0;
405 return (0);
406 }
407 }
408 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000409 xmlNodePtr *tmp;
410 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
411 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
412 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000413 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000414 return (0);
415 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000416 ctxt->nodeMax *= 2;
417 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000418 }
419 ctxt->nodeTab[ctxt->nodeNr] = value;
420 ctxt->node = value;
421 return (ctxt->nodeNr++);
422}
423static xmlNodePtr
424nodeVPop(xmlValidCtxtPtr ctxt)
425{
426 xmlNodePtr ret;
427
428 if (ctxt->nodeNr <= 0)
429 return (0);
430 ctxt->nodeNr--;
431 if (ctxt->nodeNr > 0)
432 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
433 else
434 ctxt->node = NULL;
435 ret = ctxt->nodeTab[ctxt->nodeNr];
436 ctxt->nodeTab[ctxt->nodeNr] = 0;
437 return (ret);
438}
Owen Taylor3473f882001-02-23 17:55:21 +0000439
Owen Taylor3473f882001-02-23 17:55:21 +0000440#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000441static void
442xmlValidPrintNode(xmlNodePtr cur) {
443 if (cur == NULL) {
444 xmlGenericError(xmlGenericErrorContext, "null");
445 return;
446 }
447 switch (cur->type) {
448 case XML_ELEMENT_NODE:
449 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
450 break;
451 case XML_TEXT_NODE:
452 xmlGenericError(xmlGenericErrorContext, "text ");
453 break;
454 case XML_CDATA_SECTION_NODE:
455 xmlGenericError(xmlGenericErrorContext, "cdata ");
456 break;
457 case XML_ENTITY_REF_NODE:
458 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
459 break;
460 case XML_PI_NODE:
461 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
462 break;
463 case XML_COMMENT_NODE:
464 xmlGenericError(xmlGenericErrorContext, "comment ");
465 break;
466 case XML_ATTRIBUTE_NODE:
467 xmlGenericError(xmlGenericErrorContext, "?attr? ");
468 break;
469 case XML_ENTITY_NODE:
470 xmlGenericError(xmlGenericErrorContext, "?ent? ");
471 break;
472 case XML_DOCUMENT_NODE:
473 xmlGenericError(xmlGenericErrorContext, "?doc? ");
474 break;
475 case XML_DOCUMENT_TYPE_NODE:
476 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
477 break;
478 case XML_DOCUMENT_FRAG_NODE:
479 xmlGenericError(xmlGenericErrorContext, "?frag? ");
480 break;
481 case XML_NOTATION_NODE:
482 xmlGenericError(xmlGenericErrorContext, "?nota? ");
483 break;
484 case XML_HTML_DOCUMENT_NODE:
485 xmlGenericError(xmlGenericErrorContext, "?html? ");
486 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000487#ifdef LIBXML_DOCB_ENABLED
488 case XML_DOCB_DOCUMENT_NODE:
489 xmlGenericError(xmlGenericErrorContext, "?docb? ");
490 break;
491#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000492 case XML_DTD_NODE:
493 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
494 break;
495 case XML_ELEMENT_DECL:
496 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
497 break;
498 case XML_ATTRIBUTE_DECL:
499 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
500 break;
501 case XML_ENTITY_DECL:
502 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
503 break;
504 case XML_NAMESPACE_DECL:
505 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
506 break;
507 case XML_XINCLUDE_START:
508 xmlGenericError(xmlGenericErrorContext, "incstart ");
509 break;
510 case XML_XINCLUDE_END:
511 xmlGenericError(xmlGenericErrorContext, "incend ");
512 break;
513 }
514}
515
516static void
517xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000518 if (cur == NULL)
519 xmlGenericError(xmlGenericErrorContext, "null ");
520 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000521 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000522 cur = cur->next;
523 }
524}
525
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000526static void
527xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000528 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000529
530 expr[0] = 0;
531 xmlGenericError(xmlGenericErrorContext, "valid: ");
532 xmlValidPrintNodeList(cur);
533 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000534 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000535 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
536}
537
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000538static void
539xmlValidDebugState(xmlValidStatePtr state) {
540 xmlGenericError(xmlGenericErrorContext, "(");
541 if (state->cont == NULL)
542 xmlGenericError(xmlGenericErrorContext, "null,");
543 else
544 switch (state->cont->type) {
545 case XML_ELEMENT_CONTENT_PCDATA:
546 xmlGenericError(xmlGenericErrorContext, "pcdata,");
547 break;
548 case XML_ELEMENT_CONTENT_ELEMENT:
549 xmlGenericError(xmlGenericErrorContext, "%s,",
550 state->cont->name);
551 break;
552 case XML_ELEMENT_CONTENT_SEQ:
553 xmlGenericError(xmlGenericErrorContext, "seq,");
554 break;
555 case XML_ELEMENT_CONTENT_OR:
556 xmlGenericError(xmlGenericErrorContext, "or,");
557 break;
558 }
559 xmlValidPrintNode(state->node);
560 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
561 state->depth, state->occurs, state->state);
562}
563
564static void
565xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
566 int i, j;
567
568 xmlGenericError(xmlGenericErrorContext, "state: ");
569 xmlValidDebugState(ctxt->vstate);
570 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
571 ctxt->vstateNr - 1);
572 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
573 xmlValidDebugState(&ctxt->vstateTab[j]);
574 xmlGenericError(xmlGenericErrorContext, "\n");
575}
576
577/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000578#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000579 *****/
580
581#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000582#define DEBUG_VALID_MSG(m) \
583 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
584
Owen Taylor3473f882001-02-23 17:55:21 +0000585#else
586#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000587#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000588#endif
589
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000590/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000591
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000592
Owen Taylor3473f882001-02-23 17:55:21 +0000593#define CHECK_DTD \
594 if (doc == NULL) return(0); \
595 else if ((doc->intSubset == NULL) && \
596 (doc->extSubset == NULL)) return(0)
597
Owen Taylor3473f882001-02-23 17:55:21 +0000598xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
599
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000600#ifdef LIBXML_REGEXP_ENABLED
601
602/************************************************************************
603 * *
604 * Content model validation based on the regexps *
605 * *
606 ************************************************************************/
607
608/**
609 * xmlValidBuildAContentModel:
610 * @content: the content model
611 * @ctxt: the schema parser context
612 * @name: the element name whose content is being built
613 *
614 * Generate the automata sequence needed for that type
615 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000616 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000617 */
618static int
619xmlValidBuildAContentModel(xmlElementContentPtr content,
620 xmlValidCtxtPtr ctxt,
621 const xmlChar *name) {
622 if (content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000623 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
624 "Found NULL content in content model of %s\n",
625 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000626 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000627 }
628 switch (content->type) {
629 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000630 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
631 "Found PCDATA in content model of %s\n",
632 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000633 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000634 break;
635 case XML_ELEMENT_CONTENT_ELEMENT: {
636 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000637 xmlChar fn[50];
638 xmlChar *fullname;
639
640 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
641 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000642 xmlVErrMemory(ctxt, "Building content model");
Daniel Veillardc00cda82003-04-07 10:22:39 +0000643 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000644 }
645
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000646 switch (content->ocur) {
647 case XML_ELEMENT_CONTENT_ONCE:
648 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000649 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000650 break;
651 case XML_ELEMENT_CONTENT_OPT:
652 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000653 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000654 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
655 break;
656 case XML_ELEMENT_CONTENT_PLUS:
657 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000658 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000659 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000660 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000661 break;
662 case XML_ELEMENT_CONTENT_MULT:
663 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000664 ctxt->state, fullname, NULL);
Daniel Veillard57e79b32003-02-04 15:33:12 +0000665 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
666 NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000667 break;
668 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000669 if ((fullname != fn) && (fullname != content->name))
670 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000671 break;
672 }
673 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000674 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000675 xmlElementContentOccur ocur;
676
677 /*
678 * Simply iterate over the content
679 */
680 oldstate = ctxt->state;
681 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000682 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
683 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
684 oldstate = ctxt->state;
685 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000686 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000687 xmlValidBuildAContentModel(content->c1, ctxt, name);
688 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000689 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
690 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
691 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000692 oldend = ctxt->state;
693 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000694 switch (ocur) {
695 case XML_ELEMENT_CONTENT_ONCE:
696 break;
697 case XML_ELEMENT_CONTENT_OPT:
698 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
699 break;
700 case XML_ELEMENT_CONTENT_MULT:
701 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000702 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000703 break;
704 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000705 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000706 break;
707 }
708 break;
709 }
710 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000711 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000712 xmlElementContentOccur ocur;
713
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000714 ocur = content->ocur;
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000715 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
716 (ocur == XML_ELEMENT_CONTENT_MULT)) {
717 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
718 ctxt->state, NULL);
719 }
720 oldstate = ctxt->state;
721 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000722
723 /*
724 * iterate over the subtypes and remerge the end with an
725 * epsilon transition
726 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000727 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000728 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000729 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000730 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000731 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000732 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
733 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000734 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000735 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000736 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
737 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000738 switch (ocur) {
739 case XML_ELEMENT_CONTENT_ONCE:
740 break;
741 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000742 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000743 break;
744 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000745 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
746 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000747 break;
748 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000749 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000750 break;
751 }
752 break;
753 }
754 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000755 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
756 "ContentModel broken for element %s\n",
757 (const char *) name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000758 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000759 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000760 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000761}
762/**
763 * xmlValidBuildContentModel:
764 * @ctxt: a validation context
765 * @elem: an element declaration node
766 *
767 * (Re)Build the automata associated to the content model of this
768 * element
769 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000770 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000771 */
772int
773xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000774
775 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000776 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000777 if (elem->type != XML_ELEMENT_DECL)
778 return(0);
779 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
780 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000781 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000782 if (elem->contModel != NULL) {
783 if (!xmlRegexpIsDeterminist(elem->contModel)) {
784 ctxt->valid = 0;
785 return(0);
786 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000787 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000788 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000789
790 ctxt->am = xmlNewAutomata();
791 if (ctxt->am == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000792 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
793 XML_ERR_INTERNAL_ERROR,
794 "Cannot create automata for element %s\n",
795 elem->name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000796 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000797 }
William M. Brack78637da2003-07-31 14:47:38 +0000798 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000799 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
800 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000801 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000802 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000803 char expr[5000];
804 expr[0] = 0;
805 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000806 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
807 XML_DTD_CONTENT_NOT_DETERMINIST,
808 "Content model of %s is not determinist: %s\n",
809 elem->name, BAD_CAST expr, NULL);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000810#ifdef DEBUG_REGEXP_ALGO
811 xmlRegexpPrint(stderr, elem->contModel);
812#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000813 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000814 ctxt->state = NULL;
815 xmlFreeAutomata(ctxt->am);
816 ctxt->am = NULL;
817 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000818 }
819 ctxt->state = NULL;
820 xmlFreeAutomata(ctxt->am);
821 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000822 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000823}
824
825#endif /* LIBXML_REGEXP_ENABLED */
826
Owen Taylor3473f882001-02-23 17:55:21 +0000827/****************************************************************
828 * *
829 * Util functions for data allocation/deallocation *
830 * *
831 ****************************************************************/
832
833/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000834 * xmlNewValidCtxt:
835 *
836 * Allocate a validation context structure.
837 *
838 * Returns NULL if not, otherwise the new validation context structure
839 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000840xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000841 xmlValidCtxtPtr ret;
842
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000843 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000844 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000845 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000846 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000847
848 (void) memset(ret, 0, sizeof (xmlValidCtxt));
849
850 return (ret);
851}
852
853/**
854 * xmlFreeValidCtxt:
855 * @cur: the validation context to free
856 *
857 * Free a validation context structure.
858 */
859void
860xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
861 xmlFree(cur);
862}
863
Daniel Veillard4432df22003-09-28 18:58:27 +0000864#endif /* LIBXML_VALID_ENABLED */
865
Daniel Veillarda37aab82003-06-09 09:10:36 +0000866/**
Owen Taylor3473f882001-02-23 17:55:21 +0000867 * xmlNewElementContent:
868 * @name: the subelement name or NULL
869 * @type: the type of element content decl
870 *
871 * Allocate an element content structure.
872 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000873 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000874 */
875xmlElementContentPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000876xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000877 xmlElementContentPtr ret;
878
879 switch(type) {
880 case XML_ELEMENT_CONTENT_ELEMENT:
881 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000882 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
883 "xmlNewElementContent : name == NULL !\n",
884 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000885 }
886 break;
887 case XML_ELEMENT_CONTENT_PCDATA:
888 case XML_ELEMENT_CONTENT_SEQ:
889 case XML_ELEMENT_CONTENT_OR:
890 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000891 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
892 "xmlNewElementContent : name != NULL !\n",
893 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000894 }
895 break;
896 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000897 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
898 "Internal: ELEMENT content corrupted invalid type\n",
899 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000900 return(NULL);
901 }
902 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
903 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000904 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000905 return(NULL);
906 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000907 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000908 ret->type = type;
909 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000910 if (name != NULL) {
911 xmlChar *prefix = NULL;
912 ret->name = xmlSplitQName2(name, &prefix);
913 if (ret->name == NULL)
914 ret->name = xmlStrdup(name);
915 ret->prefix = prefix;
916 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000917 ret->name = NULL;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000918 ret->prefix = NULL;
919 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000920 ret->c1 = ret->c2 = ret->parent = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000921 return(ret);
922}
923
924/**
925 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000926 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +0000927 *
928 * Build a copy of an element content description.
929 *
930 * Returns the new xmlElementContentPtr or NULL in case of error.
931 */
932xmlElementContentPtr
933xmlCopyElementContent(xmlElementContentPtr cur) {
934 xmlElementContentPtr ret;
935
936 if (cur == NULL) return(NULL);
937 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
938 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000939 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000940 return(NULL);
941 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000942 if (cur->prefix != NULL)
943 ret->prefix = xmlStrdup(cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000944 ret->ocur = cur->ocur;
945 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000946 if (ret->c1 != NULL)
947 ret->c1->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000948 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000949 if (ret->c2 != NULL)
950 ret->c2->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000951 return(ret);
952}
953
954/**
955 * xmlFreeElementContent:
956 * @cur: the element content tree to free
957 *
958 * Free an element content structure. This is a recursive call !
959 */
960void
961xmlFreeElementContent(xmlElementContentPtr cur) {
962 if (cur == NULL) return;
963 switch (cur->type) {
964 case XML_ELEMENT_CONTENT_PCDATA:
965 case XML_ELEMENT_CONTENT_ELEMENT:
966 case XML_ELEMENT_CONTENT_SEQ:
967 case XML_ELEMENT_CONTENT_OR:
968 break;
969 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000970 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
971 "Internal: ELEMENT content corrupted invalid type\n",
972 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000973 return;
974 }
975 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
976 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
977 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000978 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000979 xmlFree(cur);
980}
981
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000982#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000983/**
984 * xmlDumpElementContent:
985 * @buf: An XML buffer
986 * @content: An element table
987 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
988 *
989 * This will dump the content of the element table as an XML DTD definition
990 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000991static void
Owen Taylor3473f882001-02-23 17:55:21 +0000992xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
993 if (content == NULL) return;
994
995 if (glob) xmlBufferWriteChar(buf, "(");
996 switch (content->type) {
997 case XML_ELEMENT_CONTENT_PCDATA:
998 xmlBufferWriteChar(buf, "#PCDATA");
999 break;
1000 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001001 if (content->prefix != NULL) {
1002 xmlBufferWriteCHAR(buf, content->prefix);
1003 xmlBufferWriteChar(buf, ":");
1004 }
Owen Taylor3473f882001-02-23 17:55:21 +00001005 xmlBufferWriteCHAR(buf, content->name);
1006 break;
1007 case XML_ELEMENT_CONTENT_SEQ:
1008 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1009 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1010 xmlDumpElementContent(buf, content->c1, 1);
1011 else
1012 xmlDumpElementContent(buf, content->c1, 0);
1013 xmlBufferWriteChar(buf, " , ");
1014 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
1015 xmlDumpElementContent(buf, content->c2, 1);
1016 else
1017 xmlDumpElementContent(buf, content->c2, 0);
1018 break;
1019 case XML_ELEMENT_CONTENT_OR:
1020 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1021 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1022 xmlDumpElementContent(buf, content->c1, 1);
1023 else
1024 xmlDumpElementContent(buf, content->c1, 0);
1025 xmlBufferWriteChar(buf, " | ");
1026 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
1027 xmlDumpElementContent(buf, content->c2, 1);
1028 else
1029 xmlDumpElementContent(buf, content->c2, 0);
1030 break;
1031 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001032 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1033 "Internal: ELEMENT content corrupted invalid type\n",
1034 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001035 }
1036 if (glob)
1037 xmlBufferWriteChar(buf, ")");
1038 switch (content->ocur) {
1039 case XML_ELEMENT_CONTENT_ONCE:
1040 break;
1041 case XML_ELEMENT_CONTENT_OPT:
1042 xmlBufferWriteChar(buf, "?");
1043 break;
1044 case XML_ELEMENT_CONTENT_MULT:
1045 xmlBufferWriteChar(buf, "*");
1046 break;
1047 case XML_ELEMENT_CONTENT_PLUS:
1048 xmlBufferWriteChar(buf, "+");
1049 break;
1050 }
1051}
1052
1053/**
1054 * xmlSprintfElementContent:
1055 * @buf: an output buffer
1056 * @content: An element table
1057 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1058 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001059 * Deprecated, unsafe, use xmlSnprintfElementContent
1060 */
1061void
1062xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1063 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1064 int glob ATTRIBUTE_UNUSED) {
1065}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001066#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001067
1068/**
1069 * xmlSnprintfElementContent:
1070 * @buf: an output buffer
1071 * @size: the buffer size
1072 * @content: An element table
1073 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1074 *
Owen Taylor3473f882001-02-23 17:55:21 +00001075 * This will dump the content of the element content definition
1076 * Intended just for the debug routine
1077 */
1078void
Daniel Veillardd3d06722001-08-15 12:06:36 +00001079xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int glob) {
1080 int len;
1081
Owen Taylor3473f882001-02-23 17:55:21 +00001082 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001083 len = strlen(buf);
1084 if (size - len < 50) {
1085 if ((size - len > 4) && (buf[len - 1] != '.'))
1086 strcat(buf, " ...");
1087 return;
1088 }
Owen Taylor3473f882001-02-23 17:55:21 +00001089 if (glob) strcat(buf, "(");
1090 switch (content->type) {
1091 case XML_ELEMENT_CONTENT_PCDATA:
1092 strcat(buf, "#PCDATA");
1093 break;
1094 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001095 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001096 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001097 strcat(buf, " ...");
1098 return;
1099 }
1100 strcat(buf, (char *) content->prefix);
1101 strcat(buf, ":");
1102 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001103 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001104 strcat(buf, " ...");
1105 return;
1106 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001107 if (content->name != NULL)
1108 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001109 break;
1110 case XML_ELEMENT_CONTENT_SEQ:
1111 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1112 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001113 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001114 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001115 xmlSnprintfElementContent(buf, size, content->c1, 0);
1116 len = strlen(buf);
1117 if (size - len < 50) {
1118 if ((size - len > 4) && (buf[len - 1] != '.'))
1119 strcat(buf, " ...");
1120 return;
1121 }
Owen Taylor3473f882001-02-23 17:55:21 +00001122 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001123 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1124 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1125 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001126 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001127 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001128 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001129 break;
1130 case XML_ELEMENT_CONTENT_OR:
1131 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1132 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001133 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001134 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001135 xmlSnprintfElementContent(buf, size, content->c1, 0);
1136 len = strlen(buf);
1137 if (size - len < 50) {
1138 if ((size - len > 4) && (buf[len - 1] != '.'))
1139 strcat(buf, " ...");
1140 return;
1141 }
Owen Taylor3473f882001-02-23 17:55:21 +00001142 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001143 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1144 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1145 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001146 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001147 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001148 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001149 break;
1150 }
1151 if (glob)
1152 strcat(buf, ")");
1153 switch (content->ocur) {
1154 case XML_ELEMENT_CONTENT_ONCE:
1155 break;
1156 case XML_ELEMENT_CONTENT_OPT:
1157 strcat(buf, "?");
1158 break;
1159 case XML_ELEMENT_CONTENT_MULT:
1160 strcat(buf, "*");
1161 break;
1162 case XML_ELEMENT_CONTENT_PLUS:
1163 strcat(buf, "+");
1164 break;
1165 }
1166}
1167
1168/****************************************************************
1169 * *
1170 * Registration of DTD declarations *
1171 * *
1172 ****************************************************************/
1173
1174/**
1175 * xmlCreateElementTable:
1176 *
1177 * create and initialize an empty element hash table.
1178 *
1179 * Returns the xmlElementTablePtr just created or NULL in case of error.
1180 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001181static xmlElementTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001182xmlCreateElementTable(void) {
1183 return(xmlHashCreate(0));
1184}
1185
1186/**
1187 * xmlFreeElement:
1188 * @elem: An element
1189 *
1190 * Deallocate the memory used by an element definition
1191 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001192static void
Owen Taylor3473f882001-02-23 17:55:21 +00001193xmlFreeElement(xmlElementPtr elem) {
1194 if (elem == NULL) return;
1195 xmlUnlinkNode((xmlNodePtr) elem);
1196 xmlFreeElementContent(elem->content);
1197 if (elem->name != NULL)
1198 xmlFree((xmlChar *) elem->name);
1199 if (elem->prefix != NULL)
1200 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001201#ifdef LIBXML_REGEXP_ENABLED
1202 if (elem->contModel != NULL)
1203 xmlRegFreeRegexp(elem->contModel);
1204#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001205 xmlFree(elem);
1206}
1207
1208
1209/**
1210 * xmlAddElementDecl:
1211 * @ctxt: the validation context
1212 * @dtd: pointer to the DTD
1213 * @name: the entity name
1214 * @type: the element type
1215 * @content: the element content tree or NULL
1216 *
1217 * Register a new element declaration
1218 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001219 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001220 */
1221xmlElementPtr
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001222xmlAddElementDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1223 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001224 xmlElementTypeVal type,
1225 xmlElementContentPtr content) {
1226 xmlElementPtr ret;
1227 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001228 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001229 xmlChar *ns, *uqname;
1230
1231 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001232 return(NULL);
1233 }
1234 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001235 return(NULL);
1236 }
1237 switch (type) {
1238 case XML_ELEMENT_TYPE_EMPTY:
1239 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001240 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1241 "xmlAddElementDecl: content != NULL for EMPTY\n",
1242 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001243 return(NULL);
1244 }
1245 break;
1246 case XML_ELEMENT_TYPE_ANY:
1247 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001248 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1249 "xmlAddElementDecl: content != NULL for ANY\n",
1250 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001251 return(NULL);
1252 }
1253 break;
1254 case XML_ELEMENT_TYPE_MIXED:
1255 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001256 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1257 "xmlAddElementDecl: content == NULL for MIXED\n",
1258 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001259 return(NULL);
1260 }
1261 break;
1262 case XML_ELEMENT_TYPE_ELEMENT:
1263 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001264 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1265 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1266 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001267 return(NULL);
1268 }
1269 break;
1270 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001271 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1272 "Internal: ELEMENT decl corrupted invalid type\n",
1273 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001274 return(NULL);
1275 }
1276
1277 /*
1278 * check if name is a QName
1279 */
1280 uqname = xmlSplitQName2(name, &ns);
1281 if (uqname != NULL)
1282 name = uqname;
1283
1284 /*
1285 * Create the Element table if needed.
1286 */
1287 table = (xmlElementTablePtr) dtd->elements;
1288 if (table == NULL) {
1289 table = xmlCreateElementTable();
1290 dtd->elements = (void *) table;
1291 }
1292 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001293 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001294 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001295 if (uqname != NULL)
1296 xmlFree(uqname);
1297 if (ns != NULL)
1298 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001299 return(NULL);
1300 }
1301
Daniel Veillarda10efa82001-04-18 13:09:01 +00001302 /*
1303 * lookup old attributes inserted on an undefined element in the
1304 * internal subset.
1305 */
1306 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1307 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1308 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1309 oldAttributes = ret->attributes;
1310 ret->attributes = NULL;
1311 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1312 xmlFreeElement(ret);
1313 }
Owen Taylor3473f882001-02-23 17:55:21 +00001314 }
Owen Taylor3473f882001-02-23 17:55:21 +00001315
1316 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001317 * The element may already be present if one of its attribute
1318 * was registered first
1319 */
1320 ret = xmlHashLookup2(table, name, ns);
1321 if (ret != NULL) {
1322 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001323#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001324 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001325 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001326 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001327 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1328 "Redefinition of element %s\n",
1329 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001330#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001331 if (uqname != NULL)
1332 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001333 if (ns != NULL)
1334 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001335 return(NULL);
1336 }
1337 } else {
1338 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1339 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001340 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001341 if (uqname != NULL)
1342 xmlFree(uqname);
1343 if (ns != NULL)
1344 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001345 return(NULL);
1346 }
1347 memset(ret, 0, sizeof(xmlElement));
1348 ret->type = XML_ELEMENT_DECL;
1349
1350 /*
1351 * fill the structure.
1352 */
1353 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001354 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001355 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001356 if (uqname != NULL)
1357 xmlFree(uqname);
1358 if (ns != NULL)
1359 xmlFree(ns);
1360 xmlFree(ret);
1361 return(NULL);
1362 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001363 ret->prefix = ns;
1364
1365 /*
1366 * Validity Check:
1367 * Insertion must not fail
1368 */
1369 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001370#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001371 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001372 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001373 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001374 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1375 "Redefinition of element %s\n",
1376 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001377#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001378 xmlFreeElement(ret);
1379 if (uqname != NULL)
1380 xmlFree(uqname);
1381 return(NULL);
1382 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001383 /*
1384 * For new element, may have attributes from earlier
1385 * definition in internal subset
1386 */
1387 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001388 }
1389
1390 /*
1391 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001392 */
1393 ret->etype = type;
Owen Taylor3473f882001-02-23 17:55:21 +00001394 ret->content = xmlCopyElementContent(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001395
1396 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001397 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001398 */
1399 ret->parent = dtd;
1400 ret->doc = dtd->doc;
1401 if (dtd->last == NULL) {
1402 dtd->children = dtd->last = (xmlNodePtr) ret;
1403 } else {
1404 dtd->last->next = (xmlNodePtr) ret;
1405 ret->prev = dtd->last;
1406 dtd->last = (xmlNodePtr) ret;
1407 }
1408 if (uqname != NULL)
1409 xmlFree(uqname);
1410 return(ret);
1411}
1412
1413/**
1414 * xmlFreeElementTable:
1415 * @table: An element table
1416 *
1417 * Deallocate the memory used by an element hash table.
1418 */
1419void
1420xmlFreeElementTable(xmlElementTablePtr table) {
1421 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1422}
1423
Daniel Veillard652327a2003-09-29 18:02:38 +00001424#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001425/**
1426 * xmlCopyElement:
1427 * @elem: An element
1428 *
1429 * Build a copy of an element.
1430 *
1431 * Returns the new xmlElementPtr or NULL in case of error.
1432 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001433static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001434xmlCopyElement(xmlElementPtr elem) {
1435 xmlElementPtr cur;
1436
1437 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1438 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001439 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001440 return(NULL);
1441 }
1442 memset(cur, 0, sizeof(xmlElement));
1443 cur->type = XML_ELEMENT_DECL;
1444 cur->etype = elem->etype;
1445 if (elem->name != NULL)
1446 cur->name = xmlStrdup(elem->name);
1447 else
1448 cur->name = NULL;
1449 if (elem->prefix != NULL)
1450 cur->prefix = xmlStrdup(elem->prefix);
1451 else
1452 cur->prefix = NULL;
1453 cur->content = xmlCopyElementContent(elem->content);
1454 /* TODO : rebuild the attribute list on the copy */
1455 cur->attributes = NULL;
1456 return(cur);
1457}
1458
1459/**
1460 * xmlCopyElementTable:
1461 * @table: An element table
1462 *
1463 * Build a copy of an element table.
1464 *
1465 * Returns the new xmlElementTablePtr or NULL in case of error.
1466 */
1467xmlElementTablePtr
1468xmlCopyElementTable(xmlElementTablePtr table) {
1469 return((xmlElementTablePtr) xmlHashCopy(table,
1470 (xmlHashCopier) xmlCopyElement));
1471}
Daniel Veillard652327a2003-09-29 18:02:38 +00001472#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001473
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001474#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001475/**
1476 * xmlDumpElementDecl:
1477 * @buf: the XML buffer output
1478 * @elem: An element table
1479 *
1480 * This will dump the content of the element declaration as an XML
1481 * DTD definition
1482 */
1483void
1484xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1485 switch (elem->etype) {
1486 case XML_ELEMENT_TYPE_EMPTY:
1487 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001488 if (elem->prefix != NULL) {
1489 xmlBufferWriteCHAR(buf, elem->prefix);
1490 xmlBufferWriteChar(buf, ":");
1491 }
Owen Taylor3473f882001-02-23 17:55:21 +00001492 xmlBufferWriteCHAR(buf, elem->name);
1493 xmlBufferWriteChar(buf, " EMPTY>\n");
1494 break;
1495 case XML_ELEMENT_TYPE_ANY:
1496 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001497 if (elem->prefix != NULL) {
1498 xmlBufferWriteCHAR(buf, elem->prefix);
1499 xmlBufferWriteChar(buf, ":");
1500 }
Owen Taylor3473f882001-02-23 17:55:21 +00001501 xmlBufferWriteCHAR(buf, elem->name);
1502 xmlBufferWriteChar(buf, " ANY>\n");
1503 break;
1504 case XML_ELEMENT_TYPE_MIXED:
1505 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001506 if (elem->prefix != NULL) {
1507 xmlBufferWriteCHAR(buf, elem->prefix);
1508 xmlBufferWriteChar(buf, ":");
1509 }
Owen Taylor3473f882001-02-23 17:55:21 +00001510 xmlBufferWriteCHAR(buf, elem->name);
1511 xmlBufferWriteChar(buf, " ");
1512 xmlDumpElementContent(buf, elem->content, 1);
1513 xmlBufferWriteChar(buf, ">\n");
1514 break;
1515 case XML_ELEMENT_TYPE_ELEMENT:
1516 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001517 if (elem->prefix != NULL) {
1518 xmlBufferWriteCHAR(buf, elem->prefix);
1519 xmlBufferWriteChar(buf, ":");
1520 }
Owen Taylor3473f882001-02-23 17:55:21 +00001521 xmlBufferWriteCHAR(buf, elem->name);
1522 xmlBufferWriteChar(buf, " ");
1523 xmlDumpElementContent(buf, elem->content, 1);
1524 xmlBufferWriteChar(buf, ">\n");
1525 break;
1526 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001527 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1528 "Internal: ELEMENT struct corrupted invalid type\n",
1529 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001530 }
1531}
1532
1533/**
William M. Brack9e660592003-10-20 14:56:06 +00001534 * xmlDumpElementDeclScan:
1535 * @elem: An element table
1536 * @buf: the XML buffer output
1537 *
1538 * This routine is used by the hash scan function. It just reverses
1539 * the arguments.
1540 */
1541static void
1542xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1543 xmlDumpElementDecl(buf, elem);
1544}
1545
1546/**
Owen Taylor3473f882001-02-23 17:55:21 +00001547 * xmlDumpElementTable:
1548 * @buf: the XML buffer output
1549 * @table: An element table
1550 *
1551 * This will dump the content of the element table as an XML DTD definition
1552 */
1553void
1554xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00001555 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001556}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001557#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001558
1559/**
1560 * xmlCreateEnumeration:
1561 * @name: the enumeration name or NULL
1562 *
1563 * create and initialize an enumeration attribute node.
1564 *
1565 * Returns the xmlEnumerationPtr just created or NULL in case
1566 * of error.
1567 */
1568xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001569xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001570 xmlEnumerationPtr ret;
1571
1572 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1573 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001574 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001575 return(NULL);
1576 }
1577 memset(ret, 0, sizeof(xmlEnumeration));
1578
1579 if (name != NULL)
1580 ret->name = xmlStrdup(name);
1581 return(ret);
1582}
1583
1584/**
1585 * xmlFreeEnumeration:
1586 * @cur: the tree to free.
1587 *
1588 * free an enumeration attribute node (recursive).
1589 */
1590void
1591xmlFreeEnumeration(xmlEnumerationPtr cur) {
1592 if (cur == NULL) return;
1593
1594 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1595
1596 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001597 xmlFree(cur);
1598}
1599
Daniel Veillard652327a2003-09-29 18:02:38 +00001600#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001601/**
1602 * xmlCopyEnumeration:
1603 * @cur: the tree to copy.
1604 *
1605 * Copy an enumeration attribute node (recursive).
1606 *
1607 * Returns the xmlEnumerationPtr just created or NULL in case
1608 * of error.
1609 */
1610xmlEnumerationPtr
1611xmlCopyEnumeration(xmlEnumerationPtr cur) {
1612 xmlEnumerationPtr ret;
1613
1614 if (cur == NULL) return(NULL);
1615 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1616
1617 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1618 else ret->next = NULL;
1619
1620 return(ret);
1621}
Daniel Veillard652327a2003-09-29 18:02:38 +00001622#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001623
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001624#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001625/**
1626 * xmlDumpEnumeration:
1627 * @buf: the XML buffer output
1628 * @enum: An enumeration
1629 *
1630 * This will dump the content of the enumeration
1631 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001632static void
Owen Taylor3473f882001-02-23 17:55:21 +00001633xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1634 if (cur == NULL) return;
1635
1636 xmlBufferWriteCHAR(buf, cur->name);
1637 if (cur->next == NULL)
1638 xmlBufferWriteChar(buf, ")");
1639 else {
1640 xmlBufferWriteChar(buf, " | ");
1641 xmlDumpEnumeration(buf, cur->next);
1642 }
1643}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001644#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001645
1646/**
1647 * xmlCreateAttributeTable:
1648 *
1649 * create and initialize an empty attribute hash table.
1650 *
1651 * Returns the xmlAttributeTablePtr just created or NULL in case
1652 * of error.
1653 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001654static xmlAttributeTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001655xmlCreateAttributeTable(void) {
1656 return(xmlHashCreate(0));
1657}
1658
Daniel Veillard4432df22003-09-28 18:58:27 +00001659#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001660/**
1661 * xmlScanAttributeDeclCallback:
1662 * @attr: the attribute decl
1663 * @list: the list to update
1664 *
1665 * Callback called by xmlScanAttributeDecl when a new attribute
1666 * has to be entered in the list.
1667 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001668static void
Owen Taylor3473f882001-02-23 17:55:21 +00001669xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001670 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001671 attr->nexth = *list;
1672 *list = attr;
1673}
1674
1675/**
1676 * xmlScanAttributeDecl:
1677 * @dtd: pointer to the DTD
1678 * @elem: the element name
1679 *
1680 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001681 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001682 *
1683 * Returns the pointer to the first attribute decl in the chain,
1684 * possibly NULL.
1685 */
1686xmlAttributePtr
1687xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1688 xmlAttributePtr ret = NULL;
1689 xmlAttributeTablePtr table;
1690
1691 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001692 return(NULL);
1693 }
1694 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001695 return(NULL);
1696 }
1697 table = (xmlAttributeTablePtr) dtd->attributes;
1698 if (table == NULL)
1699 return(NULL);
1700
1701 /* WRONG !!! */
1702 xmlHashScan3(table, NULL, NULL, elem,
1703 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1704 return(ret);
1705}
1706
1707/**
1708 * xmlScanIDAttributeDecl:
1709 * @ctxt: the validation context
1710 * @elem: the element name
1711 *
1712 * Verify that the element don't have too many ID attributes
1713 * declared.
1714 *
1715 * Returns the number of ID attributes found.
1716 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001717static int
Owen Taylor3473f882001-02-23 17:55:21 +00001718xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1719 xmlAttributePtr cur;
1720 int ret = 0;
1721
1722 if (elem == NULL) return(0);
1723 cur = elem->attributes;
1724 while (cur != NULL) {
1725 if (cur->atype == XML_ATTRIBUTE_ID) {
1726 ret ++;
1727 if (ret > 1)
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001728 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001729 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001730 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001731 }
1732 cur = cur->nexth;
1733 }
1734 return(ret);
1735}
Daniel Veillard4432df22003-09-28 18:58:27 +00001736#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001737
1738/**
1739 * xmlFreeAttribute:
1740 * @elem: An attribute
1741 *
1742 * Deallocate the memory used by an attribute definition
1743 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001744static void
Owen Taylor3473f882001-02-23 17:55:21 +00001745xmlFreeAttribute(xmlAttributePtr attr) {
1746 if (attr == NULL) return;
1747 xmlUnlinkNode((xmlNodePtr) attr);
1748 if (attr->tree != NULL)
1749 xmlFreeEnumeration(attr->tree);
1750 if (attr->elem != NULL)
1751 xmlFree((xmlChar *) attr->elem);
1752 if (attr->name != NULL)
1753 xmlFree((xmlChar *) attr->name);
1754 if (attr->defaultValue != NULL)
1755 xmlFree((xmlChar *) attr->defaultValue);
1756 if (attr->prefix != NULL)
1757 xmlFree((xmlChar *) attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001758 xmlFree(attr);
1759}
1760
1761
1762/**
1763 * xmlAddAttributeDecl:
1764 * @ctxt: the validation context
1765 * @dtd: pointer to the DTD
1766 * @elem: the element name
1767 * @name: the attribute name
1768 * @ns: the attribute namespace prefix
1769 * @type: the attribute type
1770 * @def: the attribute default type
1771 * @defaultValue: the attribute default value
1772 * @tree: if it's an enumeration, the associated list
1773 *
1774 * Register a new attribute declaration
1775 * Note that @tree becomes the ownership of the DTD
1776 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001777 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001778 */
1779xmlAttributePtr
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001780xmlAddAttributeDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1781 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001782 const xmlChar *name, const xmlChar *ns,
1783 xmlAttributeType type, xmlAttributeDefault def,
1784 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1785 xmlAttributePtr ret;
1786 xmlAttributeTablePtr table;
1787 xmlElementPtr elemDef;
1788
1789 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001790 xmlFreeEnumeration(tree);
1791 return(NULL);
1792 }
1793 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001794 xmlFreeEnumeration(tree);
1795 return(NULL);
1796 }
1797 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001798 xmlFreeEnumeration(tree);
1799 return(NULL);
1800 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001801
Daniel Veillard4432df22003-09-28 18:58:27 +00001802#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001803 /*
1804 * Check the type and possibly the default value.
1805 */
1806 switch (type) {
1807 case XML_ATTRIBUTE_CDATA:
1808 break;
1809 case XML_ATTRIBUTE_ID:
1810 break;
1811 case XML_ATTRIBUTE_IDREF:
1812 break;
1813 case XML_ATTRIBUTE_IDREFS:
1814 break;
1815 case XML_ATTRIBUTE_ENTITY:
1816 break;
1817 case XML_ATTRIBUTE_ENTITIES:
1818 break;
1819 case XML_ATTRIBUTE_NMTOKEN:
1820 break;
1821 case XML_ATTRIBUTE_NMTOKENS:
1822 break;
1823 case XML_ATTRIBUTE_ENUMERATION:
1824 break;
1825 case XML_ATTRIBUTE_NOTATION:
1826 break;
1827 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001828 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1829 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1830 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001831 xmlFreeEnumeration(tree);
1832 return(NULL);
1833 }
1834 if ((defaultValue != NULL) &&
1835 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001836 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1837 "Attribute %s of %s: invalid default value\n",
1838 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00001839 defaultValue = NULL;
Daniel Veillardd01fd3e2002-02-18 22:27:47 +00001840 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001841 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001842#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001843
1844 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001845 * Check first that an attribute defined in the external subset wasn't
1846 * already defined in the internal subset
1847 */
1848 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1849 (dtd->doc->intSubset != NULL) &&
1850 (dtd->doc->intSubset->attributes != NULL)) {
1851 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1852 if (ret != NULL)
1853 return(NULL);
1854 }
1855
1856 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001857 * Create the Attribute table if needed.
1858 */
1859 table = (xmlAttributeTablePtr) dtd->attributes;
1860 if (table == NULL) {
1861 table = xmlCreateAttributeTable();
1862 dtd->attributes = (void *) table;
1863 }
1864 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001865 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001866 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001867 return(NULL);
1868 }
1869
1870
1871 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1872 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001873 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001874 return(NULL);
1875 }
1876 memset(ret, 0, sizeof(xmlAttribute));
1877 ret->type = XML_ATTRIBUTE_DECL;
1878
1879 /*
1880 * fill the structure.
1881 */
1882 ret->atype = type;
1883 ret->name = xmlStrdup(name);
1884 ret->prefix = xmlStrdup(ns);
1885 ret->elem = xmlStrdup(elem);
1886 ret->def = def;
1887 ret->tree = tree;
1888 if (defaultValue != NULL)
1889 ret->defaultValue = xmlStrdup(defaultValue);
1890
1891 /*
1892 * Validity Check:
1893 * Search the DTD for previous declarations of the ATTLIST
1894 */
1895 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001896#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001897 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001898 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00001899 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001900 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00001901 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001902 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001903#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001904 xmlFreeAttribute(ret);
1905 return(NULL);
1906 }
1907
1908 /*
1909 * Validity Check:
1910 * Multiple ID per element
1911 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001912 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001913 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00001914
Daniel Veillard4432df22003-09-28 18:58:27 +00001915#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001916 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00001917 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001918 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00001919 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001920 elem, name, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00001921 ctxt->valid = 0;
1922 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001923#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00001924
Daniel Veillard48da9102001-08-07 01:10:10 +00001925 /*
1926 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001927 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00001928 */
1929 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1930 ((ret->prefix != NULL &&
1931 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1932 ret->nexth = elemDef->attributes;
1933 elemDef->attributes = ret;
1934 } else {
1935 xmlAttributePtr tmp = elemDef->attributes;
1936
1937 while ((tmp != NULL) &&
1938 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1939 ((ret->prefix != NULL &&
1940 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1941 if (tmp->nexth == NULL)
1942 break;
1943 tmp = tmp->nexth;
1944 }
1945 if (tmp != NULL) {
1946 ret->nexth = tmp->nexth;
1947 tmp->nexth = ret;
1948 } else {
1949 ret->nexth = elemDef->attributes;
1950 elemDef->attributes = ret;
1951 }
1952 }
Owen Taylor3473f882001-02-23 17:55:21 +00001953 }
1954
1955 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001956 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001957 */
1958 ret->parent = dtd;
1959 ret->doc = dtd->doc;
1960 if (dtd->last == NULL) {
1961 dtd->children = dtd->last = (xmlNodePtr) ret;
1962 } else {
1963 dtd->last->next = (xmlNodePtr) ret;
1964 ret->prev = dtd->last;
1965 dtd->last = (xmlNodePtr) ret;
1966 }
1967 return(ret);
1968}
1969
1970/**
1971 * xmlFreeAttributeTable:
1972 * @table: An attribute table
1973 *
1974 * Deallocate the memory used by an entities hash table.
1975 */
1976void
1977xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1978 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
1979}
1980
Daniel Veillard652327a2003-09-29 18:02:38 +00001981#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001982/**
1983 * xmlCopyAttribute:
1984 * @attr: An attribute
1985 *
1986 * Build a copy of an attribute.
1987 *
1988 * Returns the new xmlAttributePtr or NULL in case of error.
1989 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001990static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001991xmlCopyAttribute(xmlAttributePtr attr) {
1992 xmlAttributePtr cur;
1993
1994 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1995 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001996 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001997 return(NULL);
1998 }
1999 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00002000 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00002001 cur->atype = attr->atype;
2002 cur->def = attr->def;
2003 cur->tree = xmlCopyEnumeration(attr->tree);
2004 if (attr->elem != NULL)
2005 cur->elem = xmlStrdup(attr->elem);
2006 if (attr->name != NULL)
2007 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002008 if (attr->prefix != NULL)
2009 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002010 if (attr->defaultValue != NULL)
2011 cur->defaultValue = xmlStrdup(attr->defaultValue);
2012 return(cur);
2013}
2014
2015/**
2016 * xmlCopyAttributeTable:
2017 * @table: An attribute table
2018 *
2019 * Build a copy of an attribute table.
2020 *
2021 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2022 */
2023xmlAttributeTablePtr
2024xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2025 return((xmlAttributeTablePtr) xmlHashCopy(table,
2026 (xmlHashCopier) xmlCopyAttribute));
2027}
Daniel Veillard652327a2003-09-29 18:02:38 +00002028#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002029
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002030#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002031/**
2032 * xmlDumpAttributeDecl:
2033 * @buf: the XML buffer output
2034 * @attr: An attribute declaration
2035 *
2036 * This will dump the content of the attribute declaration as an XML
2037 * DTD definition
2038 */
2039void
2040xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2041 xmlBufferWriteChar(buf, "<!ATTLIST ");
2042 xmlBufferWriteCHAR(buf, attr->elem);
2043 xmlBufferWriteChar(buf, " ");
2044 if (attr->prefix != NULL) {
2045 xmlBufferWriteCHAR(buf, attr->prefix);
2046 xmlBufferWriteChar(buf, ":");
2047 }
2048 xmlBufferWriteCHAR(buf, attr->name);
2049 switch (attr->atype) {
2050 case XML_ATTRIBUTE_CDATA:
2051 xmlBufferWriteChar(buf, " CDATA");
2052 break;
2053 case XML_ATTRIBUTE_ID:
2054 xmlBufferWriteChar(buf, " ID");
2055 break;
2056 case XML_ATTRIBUTE_IDREF:
2057 xmlBufferWriteChar(buf, " IDREF");
2058 break;
2059 case XML_ATTRIBUTE_IDREFS:
2060 xmlBufferWriteChar(buf, " IDREFS");
2061 break;
2062 case XML_ATTRIBUTE_ENTITY:
2063 xmlBufferWriteChar(buf, " ENTITY");
2064 break;
2065 case XML_ATTRIBUTE_ENTITIES:
2066 xmlBufferWriteChar(buf, " ENTITIES");
2067 break;
2068 case XML_ATTRIBUTE_NMTOKEN:
2069 xmlBufferWriteChar(buf, " NMTOKEN");
2070 break;
2071 case XML_ATTRIBUTE_NMTOKENS:
2072 xmlBufferWriteChar(buf, " NMTOKENS");
2073 break;
2074 case XML_ATTRIBUTE_ENUMERATION:
2075 xmlBufferWriteChar(buf, " (");
2076 xmlDumpEnumeration(buf, attr->tree);
2077 break;
2078 case XML_ATTRIBUTE_NOTATION:
2079 xmlBufferWriteChar(buf, " NOTATION (");
2080 xmlDumpEnumeration(buf, attr->tree);
2081 break;
2082 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002083 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2084 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2085 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002086 }
2087 switch (attr->def) {
2088 case XML_ATTRIBUTE_NONE:
2089 break;
2090 case XML_ATTRIBUTE_REQUIRED:
2091 xmlBufferWriteChar(buf, " #REQUIRED");
2092 break;
2093 case XML_ATTRIBUTE_IMPLIED:
2094 xmlBufferWriteChar(buf, " #IMPLIED");
2095 break;
2096 case XML_ATTRIBUTE_FIXED:
2097 xmlBufferWriteChar(buf, " #FIXED");
2098 break;
2099 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002100 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2101 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2102 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002103 }
2104 if (attr->defaultValue != NULL) {
2105 xmlBufferWriteChar(buf, " ");
2106 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2107 }
2108 xmlBufferWriteChar(buf, ">\n");
2109}
2110
2111/**
William M. Brack9e660592003-10-20 14:56:06 +00002112 * xmlDumpAttributeDeclScan:
2113 * @attr: An attribute declaration
2114 * @buf: the XML buffer output
2115 *
2116 * This is used with the hash scan function - just reverses arguments
2117 */
2118static void
2119xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2120 xmlDumpAttributeDecl(buf, attr);
2121}
2122
2123/**
Owen Taylor3473f882001-02-23 17:55:21 +00002124 * xmlDumpAttributeTable:
2125 * @buf: the XML buffer output
2126 * @table: An attribute table
2127 *
2128 * This will dump the content of the attribute table as an XML DTD definition
2129 */
2130void
2131xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002132 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002133}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002134#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002135
2136/************************************************************************
2137 * *
2138 * NOTATIONs *
2139 * *
2140 ************************************************************************/
2141/**
2142 * xmlCreateNotationTable:
2143 *
2144 * create and initialize an empty notation hash table.
2145 *
2146 * Returns the xmlNotationTablePtr just created or NULL in case
2147 * of error.
2148 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002149static xmlNotationTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002150xmlCreateNotationTable(void) {
2151 return(xmlHashCreate(0));
2152}
2153
2154/**
2155 * xmlFreeNotation:
2156 * @not: A notation
2157 *
2158 * Deallocate the memory used by an notation definition
2159 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002160static void
Owen Taylor3473f882001-02-23 17:55:21 +00002161xmlFreeNotation(xmlNotationPtr nota) {
2162 if (nota == NULL) return;
2163 if (nota->name != NULL)
2164 xmlFree((xmlChar *) nota->name);
2165 if (nota->PublicID != NULL)
2166 xmlFree((xmlChar *) nota->PublicID);
2167 if (nota->SystemID != NULL)
2168 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002169 xmlFree(nota);
2170}
2171
2172
2173/**
2174 * xmlAddNotationDecl:
2175 * @dtd: pointer to the DTD
2176 * @ctxt: the validation context
2177 * @name: the entity name
2178 * @PublicID: the public identifier or NULL
2179 * @SystemID: the system identifier or NULL
2180 *
2181 * Register a new notation declaration
2182 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002183 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002184 */
2185xmlNotationPtr
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00002186xmlAddNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002187 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002188 const xmlChar *PublicID, const xmlChar *SystemID) {
2189 xmlNotationPtr ret;
2190 xmlNotationTablePtr table;
2191
2192 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002193 return(NULL);
2194 }
2195 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002196 return(NULL);
2197 }
2198 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002199 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002200 }
2201
2202 /*
2203 * Create the Notation table if needed.
2204 */
2205 table = (xmlNotationTablePtr) dtd->notations;
2206 if (table == NULL)
2207 dtd->notations = table = xmlCreateNotationTable();
2208 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002209 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002210 "xmlAddNotationDecl: Table creation failed!\n");
2211 return(NULL);
2212 }
2213
2214 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2215 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002216 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002217 return(NULL);
2218 }
2219 memset(ret, 0, sizeof(xmlNotation));
2220
2221 /*
2222 * fill the structure.
2223 */
2224 ret->name = xmlStrdup(name);
2225 if (SystemID != NULL)
2226 ret->SystemID = xmlStrdup(SystemID);
2227 if (PublicID != NULL)
2228 ret->PublicID = xmlStrdup(PublicID);
2229
2230 /*
2231 * Validity Check:
2232 * Check the DTD for previous declarations of the ATTLIST
2233 */
2234 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002235#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002236 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2237 "xmlAddNotationDecl: %s already defined\n",
2238 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002239#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002240 xmlFreeNotation(ret);
2241 return(NULL);
2242 }
2243 return(ret);
2244}
2245
2246/**
2247 * xmlFreeNotationTable:
2248 * @table: An notation table
2249 *
2250 * Deallocate the memory used by an entities hash table.
2251 */
2252void
2253xmlFreeNotationTable(xmlNotationTablePtr table) {
2254 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2255}
2256
Daniel Veillard652327a2003-09-29 18:02:38 +00002257#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002258/**
2259 * xmlCopyNotation:
2260 * @nota: A notation
2261 *
2262 * Build a copy of a notation.
2263 *
2264 * Returns the new xmlNotationPtr or NULL in case of error.
2265 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002266static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002267xmlCopyNotation(xmlNotationPtr nota) {
2268 xmlNotationPtr cur;
2269
2270 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2271 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002272 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002273 return(NULL);
2274 }
2275 if (nota->name != NULL)
2276 cur->name = xmlStrdup(nota->name);
2277 else
2278 cur->name = NULL;
2279 if (nota->PublicID != NULL)
2280 cur->PublicID = xmlStrdup(nota->PublicID);
2281 else
2282 cur->PublicID = NULL;
2283 if (nota->SystemID != NULL)
2284 cur->SystemID = xmlStrdup(nota->SystemID);
2285 else
2286 cur->SystemID = NULL;
2287 return(cur);
2288}
2289
2290/**
2291 * xmlCopyNotationTable:
2292 * @table: A notation table
2293 *
2294 * Build a copy of a notation table.
2295 *
2296 * Returns the new xmlNotationTablePtr or NULL in case of error.
2297 */
2298xmlNotationTablePtr
2299xmlCopyNotationTable(xmlNotationTablePtr table) {
2300 return((xmlNotationTablePtr) xmlHashCopy(table,
2301 (xmlHashCopier) xmlCopyNotation));
2302}
Daniel Veillard652327a2003-09-29 18:02:38 +00002303#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002304
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002305#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002306/**
2307 * xmlDumpNotationDecl:
2308 * @buf: the XML buffer output
2309 * @nota: A notation declaration
2310 *
2311 * This will dump the content the notation declaration as an XML DTD definition
2312 */
2313void
2314xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2315 xmlBufferWriteChar(buf, "<!NOTATION ");
2316 xmlBufferWriteCHAR(buf, nota->name);
2317 if (nota->PublicID != NULL) {
2318 xmlBufferWriteChar(buf, " PUBLIC ");
2319 xmlBufferWriteQuotedString(buf, nota->PublicID);
2320 if (nota->SystemID != NULL) {
2321 xmlBufferWriteChar(buf, " ");
2322 xmlBufferWriteCHAR(buf, nota->SystemID);
2323 }
2324 } else {
2325 xmlBufferWriteChar(buf, " SYSTEM ");
2326 xmlBufferWriteCHAR(buf, nota->SystemID);
2327 }
2328 xmlBufferWriteChar(buf, " >\n");
2329}
2330
2331/**
William M. Brack9e660592003-10-20 14:56:06 +00002332 * xmlDumpNotationDeclScan:
2333 * @nota: A notation declaration
2334 * @buf: the XML buffer output
2335 *
2336 * This is called with the hash scan function, and just reverses args
2337 */
2338static void
2339xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2340 xmlDumpNotationDecl(buf, nota);
2341}
2342
2343/**
Owen Taylor3473f882001-02-23 17:55:21 +00002344 * xmlDumpNotationTable:
2345 * @buf: the XML buffer output
2346 * @table: A notation table
2347 *
2348 * This will dump the content of the notation table as an XML DTD definition
2349 */
2350void
2351xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002352 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002353}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002354#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002355
2356/************************************************************************
2357 * *
2358 * IDs *
2359 * *
2360 ************************************************************************/
2361/**
2362 * xmlCreateIDTable:
2363 *
2364 * create and initialize an empty id hash table.
2365 *
2366 * Returns the xmlIDTablePtr just created or NULL in case
2367 * of error.
2368 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002369static xmlIDTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002370xmlCreateIDTable(void) {
2371 return(xmlHashCreate(0));
2372}
2373
2374/**
2375 * xmlFreeID:
2376 * @not: A id
2377 *
2378 * Deallocate the memory used by an id definition
2379 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002380static void
Owen Taylor3473f882001-02-23 17:55:21 +00002381xmlFreeID(xmlIDPtr id) {
2382 if (id == NULL) return;
2383 if (id->value != NULL)
2384 xmlFree((xmlChar *) id->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002385 if (id->name != NULL)
2386 xmlFree((xmlChar *) id->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002387 xmlFree(id);
2388}
2389
2390/**
2391 * xmlAddID:
2392 * @ctxt: the validation context
2393 * @doc: pointer to the document
2394 * @value: the value name
2395 * @attr: the attribute holding the ID
2396 *
2397 * Register a new id declaration
2398 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002399 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002400 */
2401xmlIDPtr
2402xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2403 xmlAttrPtr attr) {
2404 xmlIDPtr ret;
2405 xmlIDTablePtr table;
2406
2407 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002408 return(NULL);
2409 }
2410 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002411 return(NULL);
2412 }
2413 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002414 return(NULL);
2415 }
2416
2417 /*
2418 * Create the ID table if needed.
2419 */
2420 table = (xmlIDTablePtr) doc->ids;
2421 if (table == NULL)
2422 doc->ids = table = xmlCreateIDTable();
2423 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002424 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002425 "xmlAddID: Table creation failed!\n");
2426 return(NULL);
2427 }
2428
2429 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2430 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002431 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002432 return(NULL);
2433 }
2434
2435 /*
2436 * fill the structure.
2437 */
2438 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002439 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2440 /*
2441 * Operating in streaming mode, attr is gonna disapear
2442 */
2443 ret->name = xmlStrdup(attr->name);
2444 ret->attr = NULL;
2445 } else {
2446 ret->attr = attr;
2447 ret->name = NULL;
2448 }
2449 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002450
2451 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002452#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002453 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002454 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002455 */
Daniel Veillard76575762002-09-05 14:21:15 +00002456 if (ctxt != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002457 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2458 "ID %s already defined\n",
2459 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002460 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002461#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002462 xmlFreeID(ret);
2463 return(NULL);
2464 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002465 if (attr != NULL)
2466 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002467 return(ret);
2468}
2469
2470/**
2471 * xmlFreeIDTable:
2472 * @table: An id table
2473 *
2474 * Deallocate the memory used by an ID hash table.
2475 */
2476void
2477xmlFreeIDTable(xmlIDTablePtr table) {
2478 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2479}
2480
2481/**
2482 * xmlIsID:
2483 * @doc: the document
2484 * @elem: the element carrying the attribute
2485 * @attr: the attribute
2486 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002487 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002488 * then this is done if DTD loading has been requested. In the case
2489 * of HTML documents parsed with the HTML parser, then ID detection is
2490 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002491 *
2492 * Returns 0 or 1 depending on the lookup result
2493 */
2494int
2495xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2496 if (doc == NULL) return(0);
2497 if (attr == NULL) return(0);
2498 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2499 return(0);
2500 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2501 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2502 (xmlStrEqual(BAD_CAST "name", attr->name)))
2503 return(1);
2504 return(0);
2505 } else {
2506 xmlAttributePtr attrDecl;
2507
2508 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002509 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002510 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002511 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002512
2513 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002514 if (fullname == NULL)
2515 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002516 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2517 attr->name);
2518 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2519 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2520 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002521 if ((fullname != fn) && (fullname != elem->name))
2522 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002523 } else {
2524 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2525 attr->name);
2526 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2527 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2528 attr->name);
2529 }
Owen Taylor3473f882001-02-23 17:55:21 +00002530
2531 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2532 return(1);
2533 }
2534 return(0);
2535}
2536
2537/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002538 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002539 * @doc: the document
2540 * @attr: the attribute
2541 *
2542 * Remove the given attribute from the ID table maintained internally.
2543 *
2544 * Returns -1 if the lookup failed and 0 otherwise
2545 */
2546int
2547xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2548 xmlAttrPtr cur;
2549 xmlIDTablePtr table;
2550 xmlChar *ID;
2551
2552 if (doc == NULL) return(-1);
2553 if (attr == NULL) return(-1);
2554 table = (xmlIDTablePtr) doc->ids;
2555 if (table == NULL)
2556 return(-1);
2557
2558 if (attr == NULL)
2559 return(-1);
2560 ID = xmlNodeListGetString(doc, attr->children, 1);
2561 if (ID == NULL)
2562 return(-1);
2563 cur = xmlHashLookup(table, ID);
2564 if (cur != attr) {
2565 xmlFree(ID);
2566 return(-1);
2567 }
2568 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
2569 xmlFree(ID);
2570 return(0);
2571}
2572
2573/**
2574 * xmlGetID:
2575 * @doc: pointer to the document
2576 * @ID: the ID value
2577 *
2578 * Search the attribute declaring the given ID
2579 *
2580 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2581 */
2582xmlAttrPtr
2583xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2584 xmlIDTablePtr table;
2585 xmlIDPtr id;
2586
2587 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002588 return(NULL);
2589 }
2590
2591 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002592 return(NULL);
2593 }
2594
2595 table = (xmlIDTablePtr) doc->ids;
2596 if (table == NULL)
2597 return(NULL);
2598
2599 id = xmlHashLookup(table, ID);
2600 if (id == NULL)
2601 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002602 if (id->attr == NULL) {
2603 /*
2604 * We are operating on a stream, return a well known reference
2605 * since the attribute node doesn't exist anymore
2606 */
2607 return((xmlAttrPtr) doc);
2608 }
Owen Taylor3473f882001-02-23 17:55:21 +00002609 return(id->attr);
2610}
2611
2612/************************************************************************
2613 * *
2614 * Refs *
2615 * *
2616 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002617typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002618{
2619 xmlListPtr l;
2620 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002621} xmlRemoveMemo;
2622
2623typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2624
2625typedef struct xmlValidateMemo_t
2626{
2627 xmlValidCtxtPtr ctxt;
2628 const xmlChar *name;
2629} xmlValidateMemo;
2630
2631typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002632
2633/**
2634 * xmlCreateRefTable:
2635 *
2636 * create and initialize an empty ref hash table.
2637 *
2638 * Returns the xmlRefTablePtr just created or NULL in case
2639 * of error.
2640 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002641static xmlRefTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002642xmlCreateRefTable(void) {
2643 return(xmlHashCreate(0));
2644}
2645
2646/**
2647 * xmlFreeRef:
2648 * @lk: A list link
2649 *
2650 * Deallocate the memory used by a ref definition
2651 */
2652static void
2653xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002654 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2655 if (ref == NULL) return;
2656 if (ref->value != NULL)
2657 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002658 if (ref->name != NULL)
2659 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002660 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002661}
2662
2663/**
2664 * xmlFreeRefList:
2665 * @list_ref: A list of references.
2666 *
2667 * Deallocate the memory used by a list of references
2668 */
2669static void
2670xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002671 if (list_ref == NULL) return;
2672 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002673}
2674
2675/**
2676 * xmlWalkRemoveRef:
2677 * @data: Contents of current link
2678 * @user: Value supplied by the user
2679 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002680 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002681 */
2682static int
2683xmlWalkRemoveRef(const void *data, const void *user)
2684{
Daniel Veillard37721922001-05-04 15:21:12 +00002685 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2686 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2687 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002688
Daniel Veillard37721922001-05-04 15:21:12 +00002689 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2690 xmlListRemoveFirst(ref_list, (void *)data);
2691 return 0;
2692 }
2693 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002694}
2695
2696/**
2697 * xmlAddRef:
2698 * @ctxt: the validation context
2699 * @doc: pointer to the document
2700 * @value: the value name
2701 * @attr: the attribute holding the Ref
2702 *
2703 * Register a new ref declaration
2704 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002705 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002706 */
2707xmlRefPtr
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00002708xmlAddRef(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002709 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002710 xmlRefPtr ret;
2711 xmlRefTablePtr table;
2712 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002713
Daniel Veillard37721922001-05-04 15:21:12 +00002714 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002715 return(NULL);
2716 }
2717 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002718 return(NULL);
2719 }
2720 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002721 return(NULL);
2722 }
Owen Taylor3473f882001-02-23 17:55:21 +00002723
Daniel Veillard37721922001-05-04 15:21:12 +00002724 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002725 * Create the Ref table if needed.
2726 */
Daniel Veillard37721922001-05-04 15:21:12 +00002727 table = (xmlRefTablePtr) doc->refs;
2728 if (table == NULL)
2729 doc->refs = table = xmlCreateRefTable();
2730 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002731 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002732 "xmlAddRef: Table creation failed!\n");
2733 return(NULL);
2734 }
Owen Taylor3473f882001-02-23 17:55:21 +00002735
Daniel Veillard37721922001-05-04 15:21:12 +00002736 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2737 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002738 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002739 return(NULL);
2740 }
Owen Taylor3473f882001-02-23 17:55:21 +00002741
Daniel Veillard37721922001-05-04 15:21:12 +00002742 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002743 * fill the structure.
2744 */
Daniel Veillard37721922001-05-04 15:21:12 +00002745 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002746 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2747 /*
2748 * Operating in streaming mode, attr is gonna disapear
2749 */
2750 ret->name = xmlStrdup(attr->name);
2751 ret->attr = NULL;
2752 } else {
2753 ret->name = NULL;
2754 ret->attr = attr;
2755 }
2756 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002757
Daniel Veillard37721922001-05-04 15:21:12 +00002758 /* To add a reference :-
2759 * References are maintained as a list of references,
2760 * Lookup the entry, if no entry create new nodelist
2761 * Add the owning node to the NodeList
2762 * Return the ref
2763 */
Owen Taylor3473f882001-02-23 17:55:21 +00002764
Daniel Veillard37721922001-05-04 15:21:12 +00002765 if (NULL == (ref_list = xmlHashLookup(table, value))) {
2766 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, NULL))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002767 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2768 "xmlAddRef: Reference list creation failed!\n",
2769 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002770 return(NULL);
2771 }
2772 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2773 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002774 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2775 "xmlAddRef: Reference list insertion failed!\n",
2776 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002777 return(NULL);
2778 }
2779 }
2780 xmlListInsert(ref_list, ret);
2781 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002782}
2783
2784/**
2785 * xmlFreeRefTable:
2786 * @table: An ref table
2787 *
2788 * Deallocate the memory used by an Ref hash table.
2789 */
2790void
2791xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002792 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002793}
2794
2795/**
2796 * xmlIsRef:
2797 * @doc: the document
2798 * @elem: the element carrying the attribute
2799 * @attr: the attribute
2800 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002801 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00002802 * then this is simple, otherwise we use an heuristic: name Ref (upper
2803 * or lowercase).
2804 *
2805 * Returns 0 or 1 depending on the lookup result
2806 */
2807int
2808xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002809 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2810 return(0);
2811 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2812 /* TODO @@@ */
2813 return(0);
2814 } else {
2815 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00002816
Daniel Veillard37721922001-05-04 15:21:12 +00002817 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2818 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2819 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2820 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002821
Daniel Veillard37721922001-05-04 15:21:12 +00002822 if ((attrDecl != NULL) &&
2823 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2824 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2825 return(1);
2826 }
2827 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002828}
2829
2830/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002831 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00002832 * @doc: the document
2833 * @attr: the attribute
2834 *
2835 * Remove the given attribute from the Ref table maintained internally.
2836 *
2837 * Returns -1 if the lookup failed and 0 otherwise
2838 */
2839int
2840xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002841 xmlListPtr ref_list;
2842 xmlRefTablePtr table;
2843 xmlChar *ID;
2844 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00002845
Daniel Veillard37721922001-05-04 15:21:12 +00002846 if (doc == NULL) return(-1);
2847 if (attr == NULL) return(-1);
2848 table = (xmlRefTablePtr) doc->refs;
2849 if (table == NULL)
2850 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002851
Daniel Veillard37721922001-05-04 15:21:12 +00002852 if (attr == NULL)
2853 return(-1);
2854 ID = xmlNodeListGetString(doc, attr->children, 1);
2855 if (ID == NULL)
2856 return(-1);
2857 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00002858
Daniel Veillard37721922001-05-04 15:21:12 +00002859 if(ref_list == NULL) {
2860 xmlFree(ID);
2861 return (-1);
2862 }
2863 /* At this point, ref_list refers to a list of references which
2864 * have the same key as the supplied attr. Our list of references
2865 * is ordered by reference address and we don't have that information
2866 * here to use when removing. We'll have to walk the list and
2867 * check for a matching attribute, when we find one stop the walk
2868 * and remove the entry.
2869 * The list is ordered by reference, so that means we don't have the
2870 * key. Passing the list and the reference to the walker means we
2871 * will have enough data to be able to remove the entry.
2872 */
2873 target.l = ref_list;
2874 target.ap = attr;
2875
2876 /* Remove the supplied attr from our list */
2877 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00002878
Daniel Veillard37721922001-05-04 15:21:12 +00002879 /*If the list is empty then remove the list entry in the hash */
2880 if (xmlListEmpty(ref_list))
2881 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2882 xmlFreeRefList);
2883 xmlFree(ID);
2884 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002885}
2886
2887/**
2888 * xmlGetRefs:
2889 * @doc: pointer to the document
2890 * @ID: the ID value
2891 *
2892 * Find the set of references for the supplied ID.
2893 *
2894 * Returns NULL if not found, otherwise node set for the ID.
2895 */
2896xmlListPtr
2897xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00002898 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00002899
Daniel Veillard37721922001-05-04 15:21:12 +00002900 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002901 return(NULL);
2902 }
Owen Taylor3473f882001-02-23 17:55:21 +00002903
Daniel Veillard37721922001-05-04 15:21:12 +00002904 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002905 return(NULL);
2906 }
Owen Taylor3473f882001-02-23 17:55:21 +00002907
Daniel Veillard37721922001-05-04 15:21:12 +00002908 table = (xmlRefTablePtr) doc->refs;
2909 if (table == NULL)
2910 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002911
Daniel Veillard37721922001-05-04 15:21:12 +00002912 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00002913}
2914
2915/************************************************************************
2916 * *
2917 * Routines for validity checking *
2918 * *
2919 ************************************************************************/
2920
2921/**
2922 * xmlGetDtdElementDesc:
2923 * @dtd: a pointer to the DtD to search
2924 * @name: the element name
2925 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002926 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002927 *
2928 * returns the xmlElementPtr if found or NULL
2929 */
2930
2931xmlElementPtr
2932xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2933 xmlElementTablePtr table;
2934 xmlElementPtr cur;
2935 xmlChar *uqname = NULL, *prefix = NULL;
2936
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002937 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002938 if (dtd->elements == NULL)
2939 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002940 table = (xmlElementTablePtr) dtd->elements;
2941
2942 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002943 if (uqname != NULL)
2944 name = uqname;
2945 cur = xmlHashLookup2(table, name, prefix);
2946 if (prefix != NULL) xmlFree(prefix);
2947 if (uqname != NULL) xmlFree(uqname);
2948 return(cur);
2949}
2950/**
2951 * xmlGetDtdElementDesc2:
2952 * @dtd: a pointer to the DtD to search
2953 * @name: the element name
2954 * @create: create an empty description if not found
2955 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002956 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00002957 *
2958 * returns the xmlElementPtr if found or NULL
2959 */
2960
Daniel Veillard86fd5a72001-12-13 14:55:21 +00002961static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00002962xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
2963 xmlElementTablePtr table;
2964 xmlElementPtr cur;
2965 xmlChar *uqname = NULL, *prefix = NULL;
2966
2967 if (dtd == NULL) return(NULL);
2968 if (dtd->elements == NULL) {
2969 if (!create)
2970 return(NULL);
2971 /*
2972 * Create the Element table if needed.
2973 */
2974 table = (xmlElementTablePtr) dtd->elements;
2975 if (table == NULL) {
2976 table = xmlCreateElementTable();
2977 dtd->elements = (void *) table;
2978 }
2979 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002980 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00002981 return(NULL);
2982 }
2983 }
2984 table = (xmlElementTablePtr) dtd->elements;
2985
2986 uqname = xmlSplitQName2(name, &prefix);
2987 if (uqname != NULL)
2988 name = uqname;
2989 cur = xmlHashLookup2(table, name, prefix);
2990 if ((cur == NULL) && (create)) {
2991 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
2992 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002993 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00002994 return(NULL);
2995 }
2996 memset(cur, 0, sizeof(xmlElement));
2997 cur->type = XML_ELEMENT_DECL;
2998
2999 /*
3000 * fill the structure.
3001 */
3002 cur->name = xmlStrdup(name);
3003 cur->prefix = xmlStrdup(prefix);
3004 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3005
3006 xmlHashAddEntry2(table, name, prefix, cur);
3007 }
3008 if (prefix != NULL) xmlFree(prefix);
3009 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003010 return(cur);
3011}
3012
3013/**
3014 * xmlGetDtdQElementDesc:
3015 * @dtd: a pointer to the DtD to search
3016 * @name: the element name
3017 * @prefix: the element namespace prefix
3018 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003019 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003020 *
3021 * returns the xmlElementPtr if found or NULL
3022 */
3023
Daniel Veillard48da9102001-08-07 01:10:10 +00003024xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003025xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3026 const xmlChar *prefix) {
3027 xmlElementTablePtr table;
3028
3029 if (dtd == NULL) return(NULL);
3030 if (dtd->elements == NULL) return(NULL);
3031 table = (xmlElementTablePtr) dtd->elements;
3032
3033 return(xmlHashLookup2(table, name, prefix));
3034}
3035
3036/**
3037 * xmlGetDtdAttrDesc:
3038 * @dtd: a pointer to the DtD to search
3039 * @elem: the element name
3040 * @name: the attribute name
3041 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003042 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003043 * this element.
3044 *
3045 * returns the xmlAttributePtr if found or NULL
3046 */
3047
3048xmlAttributePtr
3049xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3050 xmlAttributeTablePtr table;
3051 xmlAttributePtr cur;
3052 xmlChar *uqname = NULL, *prefix = NULL;
3053
3054 if (dtd == NULL) return(NULL);
3055 if (dtd->attributes == NULL) return(NULL);
3056
3057 table = (xmlAttributeTablePtr) dtd->attributes;
3058 if (table == NULL)
3059 return(NULL);
3060
3061 uqname = xmlSplitQName2(name, &prefix);
3062
3063 if (uqname != NULL) {
3064 cur = xmlHashLookup3(table, uqname, prefix, elem);
3065 if (prefix != NULL) xmlFree(prefix);
3066 if (uqname != NULL) xmlFree(uqname);
3067 } else
3068 cur = xmlHashLookup3(table, name, NULL, elem);
3069 return(cur);
3070}
3071
3072/**
3073 * xmlGetDtdQAttrDesc:
3074 * @dtd: a pointer to the DtD to search
3075 * @elem: the element name
3076 * @name: the attribute name
3077 * @prefix: the attribute namespace prefix
3078 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003079 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003080 * this element.
3081 *
3082 * returns the xmlAttributePtr if found or NULL
3083 */
3084
Daniel Veillard48da9102001-08-07 01:10:10 +00003085xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003086xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3087 const xmlChar *prefix) {
3088 xmlAttributeTablePtr table;
3089
3090 if (dtd == NULL) return(NULL);
3091 if (dtd->attributes == NULL) return(NULL);
3092 table = (xmlAttributeTablePtr) dtd->attributes;
3093
3094 return(xmlHashLookup3(table, name, prefix, elem));
3095}
3096
3097/**
3098 * xmlGetDtdNotationDesc:
3099 * @dtd: a pointer to the DtD to search
3100 * @name: the notation name
3101 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003102 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003103 *
3104 * returns the xmlNotationPtr if found or NULL
3105 */
3106
3107xmlNotationPtr
3108xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3109 xmlNotationTablePtr table;
3110
3111 if (dtd == NULL) return(NULL);
3112 if (dtd->notations == NULL) return(NULL);
3113 table = (xmlNotationTablePtr) dtd->notations;
3114
3115 return(xmlHashLookup(table, name));
3116}
3117
Daniel Veillard4432df22003-09-28 18:58:27 +00003118#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003119/**
3120 * xmlValidateNotationUse:
3121 * @ctxt: the validation context
3122 * @doc: the document
3123 * @notationName: the notation name to check
3124 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003125 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003126 * - [ VC: Notation Declared ]
3127 *
3128 * returns 1 if valid or 0 otherwise
3129 */
3130
3131int
3132xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3133 const xmlChar *notationName) {
3134 xmlNotationPtr notaDecl;
3135 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3136
3137 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3138 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3139 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3140
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003141 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003142 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3143 "NOTATION %s is not declared\n",
3144 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003145 return(0);
3146 }
3147 return(1);
3148}
Daniel Veillard4432df22003-09-28 18:58:27 +00003149#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003150
3151/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003152 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003153 * @doc: the document
3154 * @name: the element name
3155 *
3156 * Search in the DtDs whether an element accept Mixed content (or ANY)
3157 * basically if it is supposed to accept text childs
3158 *
3159 * returns 0 if no, 1 if yes, and -1 if no element description is available
3160 */
3161
3162int
3163xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3164 xmlElementPtr elemDecl;
3165
3166 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3167
3168 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3169 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3170 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3171 if (elemDecl == NULL) return(-1);
3172 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003173 case XML_ELEMENT_TYPE_UNDEFINED:
3174 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003175 case XML_ELEMENT_TYPE_ELEMENT:
3176 return(0);
3177 case XML_ELEMENT_TYPE_EMPTY:
3178 /*
3179 * return 1 for EMPTY since we want VC error to pop up
3180 * on <empty> </empty> for example
3181 */
3182 case XML_ELEMENT_TYPE_ANY:
3183 case XML_ELEMENT_TYPE_MIXED:
3184 return(1);
3185 }
3186 return(1);
3187}
3188
Daniel Veillard4432df22003-09-28 18:58:27 +00003189#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003190/**
3191 * xmlValidateNameValue:
3192 * @value: an Name value
3193 *
3194 * Validate that the given value match Name production
3195 *
3196 * returns 1 if valid or 0 otherwise
3197 */
3198
Daniel Veillard9b731d72002-04-14 12:56:08 +00003199int
Owen Taylor3473f882001-02-23 17:55:21 +00003200xmlValidateNameValue(const xmlChar *value) {
3201 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003202 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003203
3204 if (value == NULL) return(0);
3205 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003206 val = xmlStringCurrentChar(NULL, cur, &len);
3207 cur += len;
3208 if (!IS_LETTER(val) && (val != '_') &&
3209 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003210 return(0);
3211 }
3212
Daniel Veillardd8224e02002-01-13 15:43:22 +00003213 val = xmlStringCurrentChar(NULL, cur, &len);
3214 cur += len;
3215 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3216 (val == '.') || (val == '-') ||
3217 (val == '_') || (val == ':') ||
3218 (IS_COMBINING(val)) ||
3219 (IS_EXTENDER(val))) {
3220 val = xmlStringCurrentChar(NULL, cur, &len);
3221 cur += len;
3222 }
Owen Taylor3473f882001-02-23 17:55:21 +00003223
Daniel Veillardd8224e02002-01-13 15:43:22 +00003224 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003225
3226 return(1);
3227}
3228
3229/**
3230 * xmlValidateNamesValue:
3231 * @value: an Names value
3232 *
3233 * Validate that the given value match Names production
3234 *
3235 * returns 1 if valid or 0 otherwise
3236 */
3237
Daniel Veillard9b731d72002-04-14 12:56:08 +00003238int
Owen Taylor3473f882001-02-23 17:55:21 +00003239xmlValidateNamesValue(const xmlChar *value) {
3240 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003241 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003242
3243 if (value == NULL) return(0);
3244 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003245 val = xmlStringCurrentChar(NULL, cur, &len);
3246 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003247
Daniel Veillardd8224e02002-01-13 15:43:22 +00003248 if (!IS_LETTER(val) && (val != '_') &&
3249 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003250 return(0);
3251 }
3252
Daniel Veillardd8224e02002-01-13 15:43:22 +00003253 val = xmlStringCurrentChar(NULL, cur, &len);
3254 cur += len;
3255 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3256 (val == '.') || (val == '-') ||
3257 (val == '_') || (val == ':') ||
3258 (IS_COMBINING(val)) ||
3259 (IS_EXTENDER(val))) {
3260 val = xmlStringCurrentChar(NULL, cur, &len);
3261 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003262 }
3263
Daniel Veillardd8224e02002-01-13 15:43:22 +00003264 while (IS_BLANK(val)) {
3265 while (IS_BLANK(val)) {
3266 val = xmlStringCurrentChar(NULL, cur, &len);
3267 cur += len;
3268 }
3269
3270 if (!IS_LETTER(val) && (val != '_') &&
3271 (val != ':')) {
3272 return(0);
3273 }
3274 val = xmlStringCurrentChar(NULL, cur, &len);
3275 cur += len;
3276
3277 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3278 (val == '.') || (val == '-') ||
3279 (val == '_') || (val == ':') ||
3280 (IS_COMBINING(val)) ||
3281 (IS_EXTENDER(val))) {
3282 val = xmlStringCurrentChar(NULL, cur, &len);
3283 cur += len;
3284 }
3285 }
3286
3287 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003288
3289 return(1);
3290}
3291
3292/**
3293 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003294 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003295 *
3296 * Validate that the given value match Nmtoken production
3297 *
3298 * [ VC: Name Token ]
3299 *
3300 * returns 1 if valid or 0 otherwise
3301 */
3302
Daniel Veillard9b731d72002-04-14 12:56:08 +00003303int
Owen Taylor3473f882001-02-23 17:55:21 +00003304xmlValidateNmtokenValue(const xmlChar *value) {
3305 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003306 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003307
3308 if (value == NULL) return(0);
3309 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003310 val = xmlStringCurrentChar(NULL, cur, &len);
3311 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003312
Daniel Veillardd8224e02002-01-13 15:43:22 +00003313 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3314 (val != '.') && (val != '-') &&
3315 (val != '_') && (val != ':') &&
3316 (!IS_COMBINING(val)) &&
3317 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003318 return(0);
3319
Daniel Veillardd8224e02002-01-13 15:43:22 +00003320 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3321 (val == '.') || (val == '-') ||
3322 (val == '_') || (val == ':') ||
3323 (IS_COMBINING(val)) ||
3324 (IS_EXTENDER(val))) {
3325 val = xmlStringCurrentChar(NULL, cur, &len);
3326 cur += len;
3327 }
Owen Taylor3473f882001-02-23 17:55:21 +00003328
Daniel Veillardd8224e02002-01-13 15:43:22 +00003329 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003330
3331 return(1);
3332}
3333
3334/**
3335 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003336 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003337 *
3338 * Validate that the given value match Nmtokens production
3339 *
3340 * [ VC: Name Token ]
3341 *
3342 * returns 1 if valid or 0 otherwise
3343 */
3344
Daniel Veillard9b731d72002-04-14 12:56:08 +00003345int
Owen Taylor3473f882001-02-23 17:55:21 +00003346xmlValidateNmtokensValue(const xmlChar *value) {
3347 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003348 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003349
3350 if (value == NULL) return(0);
3351 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003352 val = xmlStringCurrentChar(NULL, cur, &len);
3353 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003354
Daniel Veillardd8224e02002-01-13 15:43:22 +00003355 while (IS_BLANK(val)) {
3356 val = xmlStringCurrentChar(NULL, cur, &len);
3357 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003358 }
3359
Daniel Veillardd8224e02002-01-13 15:43:22 +00003360 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3361 (val != '.') && (val != '-') &&
3362 (val != '_') && (val != ':') &&
3363 (!IS_COMBINING(val)) &&
3364 (!IS_EXTENDER(val)))
3365 return(0);
3366
3367 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3368 (val == '.') || (val == '-') ||
3369 (val == '_') || (val == ':') ||
3370 (IS_COMBINING(val)) ||
3371 (IS_EXTENDER(val))) {
3372 val = xmlStringCurrentChar(NULL, cur, &len);
3373 cur += len;
3374 }
3375
3376 while (IS_BLANK(val)) {
3377 while (IS_BLANK(val)) {
3378 val = xmlStringCurrentChar(NULL, cur, &len);
3379 cur += len;
3380 }
3381 if (val == 0) return(1);
3382
3383 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3384 (val != '.') && (val != '-') &&
3385 (val != '_') && (val != ':') &&
3386 (!IS_COMBINING(val)) &&
3387 (!IS_EXTENDER(val)))
3388 return(0);
3389
3390 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3391 (val == '.') || (val == '-') ||
3392 (val == '_') || (val == ':') ||
3393 (IS_COMBINING(val)) ||
3394 (IS_EXTENDER(val))) {
3395 val = xmlStringCurrentChar(NULL, cur, &len);
3396 cur += len;
3397 }
3398 }
3399
3400 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003401
3402 return(1);
3403}
3404
3405/**
3406 * xmlValidateNotationDecl:
3407 * @ctxt: the validation context
3408 * @doc: a document instance
3409 * @nota: a notation definition
3410 *
3411 * Try to validate a single notation definition
3412 * basically it does the following checks as described by the
3413 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003414 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003415 * But this function get called anyway ...
3416 *
3417 * returns 1 if valid or 0 otherwise
3418 */
3419
3420int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003421xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3422 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003423 int ret = 1;
3424
3425 return(ret);
3426}
3427
3428/**
3429 * xmlValidateAttributeValue:
3430 * @type: an attribute type
3431 * @value: an attribute value
3432 *
3433 * Validate that the given attribute value match the proper production
3434 *
3435 * [ VC: ID ]
3436 * Values of type ID must match the Name production....
3437 *
3438 * [ VC: IDREF ]
3439 * Values of type IDREF must match the Name production, and values
3440 * of type IDREFS must match Names ...
3441 *
3442 * [ VC: Entity Name ]
3443 * Values of type ENTITY must match the Name production, values
3444 * of type ENTITIES must match Names ...
3445 *
3446 * [ VC: Name Token ]
3447 * Values of type NMTOKEN must match the Nmtoken production; values
3448 * of type NMTOKENS must match Nmtokens.
3449 *
3450 * returns 1 if valid or 0 otherwise
3451 */
3452
3453int
3454xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3455 switch (type) {
3456 case XML_ATTRIBUTE_ENTITIES:
3457 case XML_ATTRIBUTE_IDREFS:
3458 return(xmlValidateNamesValue(value));
3459 case XML_ATTRIBUTE_ENTITY:
3460 case XML_ATTRIBUTE_IDREF:
3461 case XML_ATTRIBUTE_ID:
3462 case XML_ATTRIBUTE_NOTATION:
3463 return(xmlValidateNameValue(value));
3464 case XML_ATTRIBUTE_NMTOKENS:
3465 case XML_ATTRIBUTE_ENUMERATION:
3466 return(xmlValidateNmtokensValue(value));
3467 case XML_ATTRIBUTE_NMTOKEN:
3468 return(xmlValidateNmtokenValue(value));
3469 case XML_ATTRIBUTE_CDATA:
3470 break;
3471 }
3472 return(1);
3473}
3474
3475/**
3476 * xmlValidateAttributeValue2:
3477 * @ctxt: the validation context
3478 * @doc: the document
3479 * @name: the attribute name (used for error reporting only)
3480 * @type: the attribute type
3481 * @value: the attribute value
3482 *
3483 * Validate that the given attribute value match a given type.
3484 * This typically cannot be done before having finished parsing
3485 * the subsets.
3486 *
3487 * [ VC: IDREF ]
3488 * Values of type IDREF must match one of the declared IDs
3489 * Values of type IDREFS must match a sequence of the declared IDs
3490 * each Name must match the value of an ID attribute on some element
3491 * in the XML document; i.e. IDREF values must match the value of
3492 * some ID attribute
3493 *
3494 * [ VC: Entity Name ]
3495 * Values of type ENTITY must match one declared entity
3496 * Values of type ENTITIES must match a sequence of declared entities
3497 *
3498 * [ VC: Notation Attributes ]
3499 * all notation names in the declaration must be declared.
3500 *
3501 * returns 1 if valid or 0 otherwise
3502 */
3503
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003504static int
Owen Taylor3473f882001-02-23 17:55:21 +00003505xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3506 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3507 int ret = 1;
3508 switch (type) {
3509 case XML_ATTRIBUTE_IDREFS:
3510 case XML_ATTRIBUTE_IDREF:
3511 case XML_ATTRIBUTE_ID:
3512 case XML_ATTRIBUTE_NMTOKENS:
3513 case XML_ATTRIBUTE_ENUMERATION:
3514 case XML_ATTRIBUTE_NMTOKEN:
3515 case XML_ATTRIBUTE_CDATA:
3516 break;
3517 case XML_ATTRIBUTE_ENTITY: {
3518 xmlEntityPtr ent;
3519
3520 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003521 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003522 if ((ent == NULL) && (doc->standalone == 1)) {
3523 doc->standalone = 0;
3524 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003525 }
Owen Taylor3473f882001-02-23 17:55:21 +00003526 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003527 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3528 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003529 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003530 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003531 ret = 0;
3532 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003533 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3534 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003535 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003536 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003537 ret = 0;
3538 }
3539 break;
3540 }
3541 case XML_ATTRIBUTE_ENTITIES: {
3542 xmlChar *dup, *nam = NULL, *cur, save;
3543 xmlEntityPtr ent;
3544
3545 dup = xmlStrdup(value);
3546 if (dup == NULL)
3547 return(0);
3548 cur = dup;
3549 while (*cur != 0) {
3550 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003551 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003552 save = *cur;
3553 *cur = 0;
3554 ent = xmlGetDocEntity(doc, nam);
3555 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003556 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3557 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003558 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003559 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003560 ret = 0;
3561 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003562 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3563 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003564 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003565 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003566 ret = 0;
3567 }
3568 if (save == 0)
3569 break;
3570 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003571 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003572 }
3573 xmlFree(dup);
3574 break;
3575 }
3576 case XML_ATTRIBUTE_NOTATION: {
3577 xmlNotationPtr nota;
3578
3579 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3580 if ((nota == NULL) && (doc->extSubset != NULL))
3581 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3582
3583 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003584 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3585 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003586 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003587 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003588 ret = 0;
3589 }
3590 break;
3591 }
3592 }
3593 return(ret);
3594}
3595
3596/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003597 * xmlValidCtxtNormalizeAttributeValue:
3598 * @ctxt: the validation context
3599 * @doc: the document
3600 * @elem: the parent
3601 * @name: the attribute name
3602 * @value: the attribute value
3603 * @ctxt: the validation context or NULL
3604 *
3605 * Does the validation related extra step of the normalization of attribute
3606 * values:
3607 *
3608 * If the declared value is not CDATA, then the XML processor must further
3609 * process the normalized attribute value by discarding any leading and
3610 * trailing space (#x20) characters, and by replacing sequences of space
3611 * (#x20) characters by single space (#x20) character.
3612 *
3613 * Also check VC: Standalone Document Declaration in P32, and update
3614 * ctxt->valid accordingly
3615 *
3616 * returns a new normalized string if normalization is needed, NULL otherwise
3617 * the caller must free the returned value.
3618 */
3619
3620xmlChar *
3621xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3622 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3623 xmlChar *ret, *dst;
3624 const xmlChar *src;
3625 xmlAttributePtr attrDecl = NULL;
3626 int extsubset = 0;
3627
3628 if (doc == NULL) return(NULL);
3629 if (elem == NULL) return(NULL);
3630 if (name == NULL) return(NULL);
3631 if (value == NULL) return(NULL);
3632
3633 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003634 xmlChar fn[50];
3635 xmlChar *fullname;
3636
3637 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3638 if (fullname == NULL)
3639 return(0);
3640 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003641 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003642 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003643 if (attrDecl != NULL)
3644 extsubset = 1;
3645 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003646 if ((fullname != fn) && (fullname != elem->name))
3647 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003648 }
3649 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3650 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3651 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3652 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3653 if (attrDecl != NULL)
3654 extsubset = 1;
3655 }
3656
3657 if (attrDecl == NULL)
3658 return(NULL);
3659 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3660 return(NULL);
3661
3662 ret = xmlStrdup(value);
3663 if (ret == NULL)
3664 return(NULL);
3665 src = value;
3666 dst = ret;
3667 while (*src == 0x20) src++;
3668 while (*src != 0) {
3669 if (*src == 0x20) {
3670 while (*src == 0x20) src++;
3671 if (*src != 0)
3672 *dst++ = 0x20;
3673 } else {
3674 *dst++ = *src++;
3675 }
3676 }
3677 *dst = 0;
3678 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003679 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003680"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003681 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003682 ctxt->valid = 0;
3683 }
3684 return(ret);
3685}
3686
3687/**
Owen Taylor3473f882001-02-23 17:55:21 +00003688 * xmlValidNormalizeAttributeValue:
3689 * @doc: the document
3690 * @elem: the parent
3691 * @name: the attribute name
3692 * @value: the attribute value
3693 *
3694 * Does the validation related extra step of the normalization of attribute
3695 * values:
3696 *
3697 * If the declared value is not CDATA, then the XML processor must further
3698 * process the normalized attribute value by discarding any leading and
3699 * trailing space (#x20) characters, and by replacing sequences of space
3700 * (#x20) characters by single space (#x20) character.
3701 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003702 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003703 * the caller must free the returned value.
3704 */
3705
3706xmlChar *
3707xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3708 const xmlChar *name, const xmlChar *value) {
3709 xmlChar *ret, *dst;
3710 const xmlChar *src;
3711 xmlAttributePtr attrDecl = NULL;
3712
3713 if (doc == NULL) return(NULL);
3714 if (elem == NULL) return(NULL);
3715 if (name == NULL) return(NULL);
3716 if (value == NULL) return(NULL);
3717
3718 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003719 xmlChar fn[50];
3720 xmlChar *fullname;
3721
3722 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3723 if (fullname == NULL)
3724 return(0);
3725 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003726 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003727 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3728 if ((fullname != fn) && (fullname != elem->name))
3729 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003730 }
3731 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3732 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3733 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3734
3735 if (attrDecl == NULL)
3736 return(NULL);
3737 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3738 return(NULL);
3739
3740 ret = xmlStrdup(value);
3741 if (ret == NULL)
3742 return(NULL);
3743 src = value;
3744 dst = ret;
3745 while (*src == 0x20) src++;
3746 while (*src != 0) {
3747 if (*src == 0x20) {
3748 while (*src == 0x20) src++;
3749 if (*src != 0)
3750 *dst++ = 0x20;
3751 } else {
3752 *dst++ = *src++;
3753 }
3754 }
3755 *dst = 0;
3756 return(ret);
3757}
3758
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003759static void
Owen Taylor3473f882001-02-23 17:55:21 +00003760xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003761 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003762 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3763}
3764
3765/**
3766 * xmlValidateAttributeDecl:
3767 * @ctxt: the validation context
3768 * @doc: a document instance
3769 * @attr: an attribute definition
3770 *
3771 * Try to validate a single attribute definition
3772 * basically it does the following checks as described by the
3773 * XML-1.0 recommendation:
3774 * - [ VC: Attribute Default Legal ]
3775 * - [ VC: Enumeration ]
3776 * - [ VC: ID Attribute Default ]
3777 *
3778 * The ID/IDREF uniqueness and matching are done separately
3779 *
3780 * returns 1 if valid or 0 otherwise
3781 */
3782
3783int
3784xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3785 xmlAttributePtr attr) {
3786 int ret = 1;
3787 int val;
3788 CHECK_DTD;
3789 if(attr == NULL) return(1);
3790
3791 /* Attribute Default Legal */
3792 /* Enumeration */
3793 if (attr->defaultValue != NULL) {
3794 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3795 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003796 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003797 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003798 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003799 }
3800 ret &= val;
3801 }
3802
3803 /* ID Attribute Default */
3804 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3805 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3806 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003807 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003808 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003809 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003810 ret = 0;
3811 }
3812
3813 /* One ID per Element Type */
3814 if (attr->atype == XML_ATTRIBUTE_ID) {
3815 int nbId;
3816
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003817 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00003818 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3819 attr->elem);
3820 if (elem != NULL) {
3821 nbId = xmlScanIDAttributeDecl(NULL, elem);
3822 } else {
3823 xmlAttributeTablePtr table;
3824
3825 /*
3826 * The attribute may be declared in the internal subset and the
3827 * element in the external subset.
3828 */
3829 nbId = 0;
3830 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3831 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3832 xmlValidateAttributeIdCallback, &nbId);
3833 }
3834 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003835
3836 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003837 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3838 attr->elem, nbId, attr->name);
3839 } else if (doc->extSubset != NULL) {
3840 int extId = 0;
3841 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3842 if (elem != NULL) {
3843 extId = xmlScanIDAttributeDecl(NULL, elem);
3844 }
3845 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003846 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003847 "Element %s has %d ID attribute defined in the external subset : %s\n",
3848 attr->elem, extId, attr->name);
3849 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003850 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003851"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003852 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003853 }
3854 }
3855 }
3856
3857 /* Validity Constraint: Enumeration */
3858 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3859 xmlEnumerationPtr tree = attr->tree;
3860 while (tree != NULL) {
3861 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3862 tree = tree->next;
3863 }
3864 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003865 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003866"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003867 attr->defaultValue, attr->name, attr->elem);
3868 ret = 0;
3869 }
3870 }
3871
3872 return(ret);
3873}
3874
3875/**
3876 * xmlValidateElementDecl:
3877 * @ctxt: the validation context
3878 * @doc: a document instance
3879 * @elem: an element definition
3880 *
3881 * Try to validate a single element definition
3882 * basically it does the following checks as described by the
3883 * XML-1.0 recommendation:
3884 * - [ VC: One ID per Element Type ]
3885 * - [ VC: No Duplicate Types ]
3886 * - [ VC: Unique Element Type Declaration ]
3887 *
3888 * returns 1 if valid or 0 otherwise
3889 */
3890
3891int
3892xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3893 xmlElementPtr elem) {
3894 int ret = 1;
3895 xmlElementPtr tst;
3896
3897 CHECK_DTD;
3898
3899 if (elem == NULL) return(1);
3900
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003901#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00003902#ifdef LIBXML_REGEXP_ENABLED
3903 /* Build the regexp associated to the content model */
3904 ret = xmlValidBuildContentModel(ctxt, elem);
3905#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003906#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00003907
Owen Taylor3473f882001-02-23 17:55:21 +00003908 /* No Duplicate Types */
3909 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3910 xmlElementContentPtr cur, next;
3911 const xmlChar *name;
3912
3913 cur = elem->content;
3914 while (cur != NULL) {
3915 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3916 if (cur->c1 == NULL) break;
3917 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3918 name = cur->c1->name;
3919 next = cur->c2;
3920 while (next != NULL) {
3921 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00003922 if ((xmlStrEqual(next->name, name)) &&
3923 (xmlStrEqual(next->prefix, cur->prefix))) {
3924 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003925 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00003926 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003927 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003928 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003929 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003930 "Definition of %s has duplicate references of %s:%s\n",
3931 elem->name, cur->prefix, name);
3932 }
Owen Taylor3473f882001-02-23 17:55:21 +00003933 ret = 0;
3934 }
3935 break;
3936 }
3937 if (next->c1 == NULL) break;
3938 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00003939 if ((xmlStrEqual(next->c1->name, name)) &&
3940 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
3941 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003942 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003943 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003944 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003945 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003946 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003947 "Definition of %s has duplicate references to %s:%s\n",
3948 elem->name, cur->prefix, name);
3949 }
Owen Taylor3473f882001-02-23 17:55:21 +00003950 ret = 0;
3951 }
3952 next = next->c2;
3953 }
3954 }
3955 cur = cur->c2;
3956 }
3957 }
3958
3959 /* VC: Unique Element Type Declaration */
3960 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003961 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00003962 ((tst->prefix == elem->prefix) ||
3963 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00003964 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003965 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
3966 "Redefinition of element %s\n",
3967 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003968 ret = 0;
3969 }
3970 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003971 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00003972 ((tst->prefix == elem->prefix) ||
3973 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00003974 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003975 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
3976 "Redefinition of element %s\n",
3977 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003978 ret = 0;
3979 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00003980 /* One ID per Element Type
3981 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00003982 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3983 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00003984 } */
Owen Taylor3473f882001-02-23 17:55:21 +00003985 return(ret);
3986}
3987
3988/**
3989 * xmlValidateOneAttribute:
3990 * @ctxt: the validation context
3991 * @doc: a document instance
3992 * @elem: an element instance
3993 * @attr: an attribute instance
3994 * @value: the attribute value (without entities processing)
3995 *
3996 * Try to validate a single attribute for an element
3997 * basically it does the following checks as described by the
3998 * XML-1.0 recommendation:
3999 * - [ VC: Attribute Value Type ]
4000 * - [ VC: Fixed Attribute Default ]
4001 * - [ VC: Entity Name ]
4002 * - [ VC: Name Token ]
4003 * - [ VC: ID ]
4004 * - [ VC: IDREF ]
4005 * - [ VC: Entity Name ]
4006 * - [ VC: Notation Attributes ]
4007 *
4008 * The ID/IDREF uniqueness and matching are done separately
4009 *
4010 * returns 1 if valid or 0 otherwise
4011 */
4012
4013int
4014xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004015 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4016{
Owen Taylor3473f882001-02-23 17:55:21 +00004017 xmlAttributePtr attrDecl = NULL;
4018 int val;
4019 int ret = 1;
4020
4021 CHECK_DTD;
4022 if ((elem == NULL) || (elem->name == NULL)) return(0);
4023 if ((attr == NULL) || (attr->name == NULL)) return(0);
4024
4025 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004026 xmlChar fn[50];
4027 xmlChar *fullname;
4028
4029 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4030 if (fullname == NULL)
4031 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004032 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004033 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004034 attr->name, attr->ns->prefix);
4035 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004036 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004037 attr->name, attr->ns->prefix);
4038 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004039 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004040 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4041 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004042 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004043 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004044 if ((fullname != fn) && (fullname != elem->name))
4045 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004046 }
4047 if (attrDecl == NULL) {
4048 if (attr->ns != NULL) {
4049 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4050 attr->name, attr->ns->prefix);
4051 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4052 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4053 attr->name, attr->ns->prefix);
4054 } else {
4055 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4056 elem->name, attr->name);
4057 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4058 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4059 elem->name, attr->name);
4060 }
4061 }
4062
4063
4064 /* Validity Constraint: Attribute Value Type */
4065 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004066 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004067 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004068 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004069 return(0);
4070 }
4071 attr->atype = attrDecl->atype;
4072
4073 val = xmlValidateAttributeValue(attrDecl->atype, value);
4074 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004075 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004076 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004077 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004078 ret = 0;
4079 }
4080
4081 /* Validity constraint: Fixed Attribute Default */
4082 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4083 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004084 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004085 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004086 attr->name, elem->name, attrDecl->defaultValue);
4087 ret = 0;
4088 }
4089 }
4090
4091 /* Validity Constraint: ID uniqueness */
4092 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4093 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4094 ret = 0;
4095 }
4096
4097 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4098 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4099 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4100 ret = 0;
4101 }
4102
4103 /* Validity Constraint: Notation Attributes */
4104 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4105 xmlEnumerationPtr tree = attrDecl->tree;
4106 xmlNotationPtr nota;
4107
4108 /* First check that the given NOTATION was declared */
4109 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4110 if (nota == NULL)
4111 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4112
4113 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004114 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004115 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004116 value, attr->name, elem->name);
4117 ret = 0;
4118 }
4119
4120 /* Second, verify that it's among the list */
4121 while (tree != NULL) {
4122 if (xmlStrEqual(tree->name, value)) break;
4123 tree = tree->next;
4124 }
4125 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004126 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004127"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004128 value, attr->name, elem->name);
4129 ret = 0;
4130 }
4131 }
4132
4133 /* Validity Constraint: Enumeration */
4134 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4135 xmlEnumerationPtr tree = attrDecl->tree;
4136 while (tree != NULL) {
4137 if (xmlStrEqual(tree->name, value)) break;
4138 tree = tree->next;
4139 }
4140 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004141 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004142 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004143 value, attr->name, elem->name);
4144 ret = 0;
4145 }
4146 }
4147
4148 /* Fixed Attribute Default */
4149 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4150 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004151 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004152 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004153 attr->name, elem->name, attrDecl->defaultValue);
4154 ret = 0;
4155 }
4156
4157 /* Extra check for the attribute value */
4158 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4159 attrDecl->atype, value);
4160
4161 return(ret);
4162}
4163
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004164/**
4165 * xmlValidateOneNamespace:
4166 * @ctxt: the validation context
4167 * @doc: a document instance
4168 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004169 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004170 * @ns: an namespace declaration instance
4171 * @value: the attribute value (without entities processing)
4172 *
4173 * Try to validate a single namespace declaration for an element
4174 * basically it does the following checks as described by the
4175 * XML-1.0 recommendation:
4176 * - [ VC: Attribute Value Type ]
4177 * - [ VC: Fixed Attribute Default ]
4178 * - [ VC: Entity Name ]
4179 * - [ VC: Name Token ]
4180 * - [ VC: ID ]
4181 * - [ VC: IDREF ]
4182 * - [ VC: Entity Name ]
4183 * - [ VC: Notation Attributes ]
4184 *
4185 * The ID/IDREF uniqueness and matching are done separately
4186 *
4187 * returns 1 if valid or 0 otherwise
4188 */
4189
4190int
4191xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4192xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4193 /* xmlElementPtr elemDecl; */
4194 xmlAttributePtr attrDecl = NULL;
4195 int val;
4196 int ret = 1;
4197
4198 CHECK_DTD;
4199 if ((elem == NULL) || (elem->name == NULL)) return(0);
4200 if ((ns == NULL) || (ns->href == NULL)) return(0);
4201
4202 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004203 xmlChar fn[50];
4204 xmlChar *fullname;
4205
4206 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4207 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004208 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004209 return(0);
4210 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004211 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004212 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004213 ns->prefix, BAD_CAST "xmlns");
4214 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004215 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004216 ns->prefix, BAD_CAST "xmlns");
4217 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004218 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004219 BAD_CAST "xmlns");
4220 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004221 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004222 BAD_CAST "xmlns");
4223 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004224 if ((fullname != fn) && (fullname != elem->name))
4225 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004226 }
4227 if (attrDecl == NULL) {
4228 if (ns->prefix != NULL) {
4229 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4230 ns->prefix, BAD_CAST "xmlns");
4231 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4232 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4233 ns->prefix, BAD_CAST "xmlns");
4234 } else {
4235 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4236 elem->name, BAD_CAST "xmlns");
4237 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4238 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4239 elem->name, BAD_CAST "xmlns");
4240 }
4241 }
4242
4243
4244 /* Validity Constraint: Attribute Value Type */
4245 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004246 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004247 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004248 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004249 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004250 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004251 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004252 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004253 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004254 }
4255 return(0);
4256 }
4257
4258 val = xmlValidateAttributeValue(attrDecl->atype, value);
4259 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004260 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004261 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004262 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004263 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004264 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004265 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004266 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004267 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004268 }
4269 ret = 0;
4270 }
4271
4272 /* Validity constraint: Fixed Attribute Default */
4273 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4274 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004275 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004276 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004277 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4278 ns->prefix, elem->name, attrDecl->defaultValue);
4279 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004280 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004281 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004282 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004283 }
4284 ret = 0;
4285 }
4286 }
4287
4288 /* Validity Constraint: ID uniqueness */
4289 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4290 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4291 ret = 0;
4292 }
4293
4294 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4295 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4296 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4297 ret = 0;
4298 }
4299
4300 /* Validity Constraint: Notation Attributes */
4301 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4302 xmlEnumerationPtr tree = attrDecl->tree;
4303 xmlNotationPtr nota;
4304
4305 /* First check that the given NOTATION was declared */
4306 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4307 if (nota == NULL)
4308 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4309
4310 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004311 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004312 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004313 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4314 value, ns->prefix, elem->name);
4315 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004316 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004317 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004318 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004319 }
4320 ret = 0;
4321 }
4322
4323 /* Second, verify that it's among the list */
4324 while (tree != NULL) {
4325 if (xmlStrEqual(tree->name, value)) break;
4326 tree = tree->next;
4327 }
4328 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004329 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004330 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004331"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4332 value, ns->prefix, elem->name);
4333 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004334 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004335"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004336 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004337 }
4338 ret = 0;
4339 }
4340 }
4341
4342 /* Validity Constraint: Enumeration */
4343 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4344 xmlEnumerationPtr tree = attrDecl->tree;
4345 while (tree != NULL) {
4346 if (xmlStrEqual(tree->name, value)) break;
4347 tree = tree->next;
4348 }
4349 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004350 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004351 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004352"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4353 value, ns->prefix, elem->name);
4354 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004355 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004356"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004357 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004358 }
4359 ret = 0;
4360 }
4361 }
4362
4363 /* Fixed Attribute Default */
4364 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4365 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004366 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004367 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004368 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4369 ns->prefix, elem->name, attrDecl->defaultValue);
4370 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004371 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004372 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004373 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004374 }
4375 ret = 0;
4376 }
4377
4378 /* Extra check for the attribute value */
4379 if (ns->prefix != NULL) {
4380 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4381 attrDecl->atype, value);
4382 } else {
4383 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4384 attrDecl->atype, value);
4385 }
4386
4387 return(ret);
4388}
4389
Daniel Veillard118aed72002-09-24 14:13:13 +00004390#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004391/**
4392 * xmlValidateSkipIgnorable:
4393 * @ctxt: the validation context
4394 * @child: the child list
4395 *
4396 * Skip ignorable elements w.r.t. the validation process
4397 *
4398 * returns the first element to consider for validation of the content model
4399 */
4400
4401static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004402xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004403 while (child != NULL) {
4404 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004405 /* These things are ignored (skipped) during validation. */
4406 case XML_PI_NODE:
4407 case XML_COMMENT_NODE:
4408 case XML_XINCLUDE_START:
4409 case XML_XINCLUDE_END:
4410 child = child->next;
4411 break;
4412 case XML_TEXT_NODE:
4413 if (xmlIsBlankNode(child))
4414 child = child->next;
4415 else
4416 return(child);
4417 break;
4418 /* keep current node */
4419 default:
4420 return(child);
4421 }
4422 }
4423 return(child);
4424}
4425
4426/**
4427 * xmlValidateElementType:
4428 * @ctxt: the validation context
4429 *
4430 * Try to validate the content model of an element internal function
4431 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004432 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4433 * reference is found and -3 if the validation succeeded but
4434 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004435 */
4436
4437static int
4438xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004439 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004440 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004441
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004442 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004443 if ((NODE == NULL) && (CONT == NULL))
4444 return(1);
4445 if ((NODE == NULL) &&
4446 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4447 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4448 return(1);
4449 }
4450 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004451 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004452 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004453
4454 /*
4455 * We arrive here when more states need to be examined
4456 */
4457cont:
4458
4459 /*
4460 * We just recovered from a rollback generated by a possible
4461 * epsilon transition, go directly to the analysis phase
4462 */
4463 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004464 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004465 DEBUG_VALID_STATE(NODE, CONT)
4466 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004467 goto analyze;
4468 }
4469
4470 DEBUG_VALID_STATE(NODE, CONT)
4471 /*
4472 * we may have to save a backup state here. This is the equivalent
4473 * of handling epsilon transition in NFAs.
4474 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004475 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004476 ((CONT->parent == NULL) ||
4477 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004478 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004479 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004480 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004481 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004482 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4483 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004484 }
4485
4486
4487 /*
4488 * Check first if the content matches
4489 */
4490 switch (CONT->type) {
4491 case XML_ELEMENT_CONTENT_PCDATA:
4492 if (NODE == NULL) {
4493 DEBUG_VALID_MSG("pcdata failed no node");
4494 ret = 0;
4495 break;
4496 }
4497 if (NODE->type == XML_TEXT_NODE) {
4498 DEBUG_VALID_MSG("pcdata found, skip to next");
4499 /*
4500 * go to next element in the content model
4501 * skipping ignorable elems
4502 */
4503 do {
4504 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004505 NODE = xmlValidateSkipIgnorable(NODE);
4506 if ((NODE != NULL) &&
4507 (NODE->type == XML_ENTITY_REF_NODE))
4508 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004509 } while ((NODE != NULL) &&
4510 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004511 (NODE->type != XML_TEXT_NODE) &&
4512 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004513 ret = 1;
4514 break;
4515 } else {
4516 DEBUG_VALID_MSG("pcdata failed");
4517 ret = 0;
4518 break;
4519 }
4520 break;
4521 case XML_ELEMENT_CONTENT_ELEMENT:
4522 if (NODE == NULL) {
4523 DEBUG_VALID_MSG("element failed no node");
4524 ret = 0;
4525 break;
4526 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004527 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4528 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004529 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004530 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4531 ret = (CONT->prefix == NULL);
4532 } else if (CONT->prefix == NULL) {
4533 ret = 0;
4534 } else {
4535 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4536 }
4537 }
4538 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004539 DEBUG_VALID_MSG("element found, skip to next");
4540 /*
4541 * go to next element in the content model
4542 * skipping ignorable elems
4543 */
4544 do {
4545 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004546 NODE = xmlValidateSkipIgnorable(NODE);
4547 if ((NODE != NULL) &&
4548 (NODE->type == XML_ENTITY_REF_NODE))
4549 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004550 } while ((NODE != NULL) &&
4551 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004552 (NODE->type != XML_TEXT_NODE) &&
4553 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004554 } else {
4555 DEBUG_VALID_MSG("element failed");
4556 ret = 0;
4557 break;
4558 }
4559 break;
4560 case XML_ELEMENT_CONTENT_OR:
4561 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004562 * Small optimization.
4563 */
4564 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4565 if ((NODE == NULL) ||
4566 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4567 DEPTH++;
4568 CONT = CONT->c2;
4569 goto cont;
4570 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004571 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4572 ret = (CONT->c1->prefix == NULL);
4573 } else if (CONT->c1->prefix == NULL) {
4574 ret = 0;
4575 } else {
4576 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4577 }
4578 if (ret == 0) {
4579 DEPTH++;
4580 CONT = CONT->c2;
4581 goto cont;
4582 }
Daniel Veillard85349052001-04-20 13:48:21 +00004583 }
4584
4585 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004586 * save the second branch 'or' branch
4587 */
4588 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004589 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4590 OCCURS, ROLLBACK_OR) < 0)
4591 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004592 DEPTH++;
4593 CONT = CONT->c1;
4594 goto cont;
4595 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004596 /*
4597 * Small optimization.
4598 */
4599 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4600 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4601 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4602 if ((NODE == NULL) ||
4603 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4604 DEPTH++;
4605 CONT = CONT->c2;
4606 goto cont;
4607 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004608 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4609 ret = (CONT->c1->prefix == NULL);
4610 } else if (CONT->c1->prefix == NULL) {
4611 ret = 0;
4612 } else {
4613 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4614 }
4615 if (ret == 0) {
4616 DEPTH++;
4617 CONT = CONT->c2;
4618 goto cont;
4619 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004620 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004621 DEPTH++;
4622 CONT = CONT->c1;
4623 goto cont;
4624 }
4625
4626 /*
4627 * At this point handle going up in the tree
4628 */
4629 if (ret == -1) {
4630 DEBUG_VALID_MSG("error found returning");
4631 return(ret);
4632 }
4633analyze:
4634 while (CONT != NULL) {
4635 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004636 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004637 * this level.
4638 */
4639 if (ret == 0) {
4640 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004641 xmlNodePtr cur;
4642
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004643 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004644 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004645 DEBUG_VALID_MSG("Once branch failed, rollback");
4646 if (vstateVPop(ctxt) < 0 ) {
4647 DEBUG_VALID_MSG("exhaustion, failed");
4648 return(0);
4649 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004650 if (cur != ctxt->vstate->node)
4651 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004652 goto cont;
4653 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004654 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004655 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004656 DEBUG_VALID_MSG("Plus branch failed, rollback");
4657 if (vstateVPop(ctxt) < 0 ) {
4658 DEBUG_VALID_MSG("exhaustion, failed");
4659 return(0);
4660 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004661 if (cur != ctxt->vstate->node)
4662 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004663 goto cont;
4664 }
4665 DEBUG_VALID_MSG("Plus branch found");
4666 ret = 1;
4667 break;
4668 case XML_ELEMENT_CONTENT_MULT:
4669#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004670 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004671 DEBUG_VALID_MSG("Mult branch failed");
4672 } else {
4673 DEBUG_VALID_MSG("Mult branch found");
4674 }
4675#endif
4676 ret = 1;
4677 break;
4678 case XML_ELEMENT_CONTENT_OPT:
4679 DEBUG_VALID_MSG("Option branch failed");
4680 ret = 1;
4681 break;
4682 }
4683 } else {
4684 switch (CONT->ocur) {
4685 case XML_ELEMENT_CONTENT_OPT:
4686 DEBUG_VALID_MSG("Option branch succeeded");
4687 ret = 1;
4688 break;
4689 case XML_ELEMENT_CONTENT_ONCE:
4690 DEBUG_VALID_MSG("Once branch succeeded");
4691 ret = 1;
4692 break;
4693 case XML_ELEMENT_CONTENT_PLUS:
4694 if (STATE == ROLLBACK_PARENT) {
4695 DEBUG_VALID_MSG("Plus branch rollback");
4696 ret = 1;
4697 break;
4698 }
4699 if (NODE == NULL) {
4700 DEBUG_VALID_MSG("Plus branch exhausted");
4701 ret = 1;
4702 break;
4703 }
4704 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004705 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004706 goto cont;
4707 case XML_ELEMENT_CONTENT_MULT:
4708 if (STATE == ROLLBACK_PARENT) {
4709 DEBUG_VALID_MSG("Mult branch rollback");
4710 ret = 1;
4711 break;
4712 }
4713 if (NODE == NULL) {
4714 DEBUG_VALID_MSG("Mult branch exhausted");
4715 ret = 1;
4716 break;
4717 }
4718 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004719 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004720 goto cont;
4721 }
4722 }
4723 STATE = 0;
4724
4725 /*
4726 * Then act accordingly at the parent level
4727 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004728 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004729 if (CONT->parent == NULL)
4730 break;
4731
4732 switch (CONT->parent->type) {
4733 case XML_ELEMENT_CONTENT_PCDATA:
4734 DEBUG_VALID_MSG("Error: parent pcdata");
4735 return(-1);
4736 case XML_ELEMENT_CONTENT_ELEMENT:
4737 DEBUG_VALID_MSG("Error: parent element");
4738 return(-1);
4739 case XML_ELEMENT_CONTENT_OR:
4740 if (ret == 1) {
4741 DEBUG_VALID_MSG("Or succeeded");
4742 CONT = CONT->parent;
4743 DEPTH--;
4744 } else {
4745 DEBUG_VALID_MSG("Or failed");
4746 CONT = CONT->parent;
4747 DEPTH--;
4748 }
4749 break;
4750 case XML_ELEMENT_CONTENT_SEQ:
4751 if (ret == 0) {
4752 DEBUG_VALID_MSG("Sequence failed");
4753 CONT = CONT->parent;
4754 DEPTH--;
4755 } else if (CONT == CONT->parent->c1) {
4756 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4757 CONT = CONT->parent->c2;
4758 goto cont;
4759 } else {
4760 DEBUG_VALID_MSG("Sequence succeeded");
4761 CONT = CONT->parent;
4762 DEPTH--;
4763 }
4764 }
4765 }
4766 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004767 xmlNodePtr cur;
4768
4769 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004770 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4771 if (vstateVPop(ctxt) < 0 ) {
4772 DEBUG_VALID_MSG("exhaustion, failed");
4773 return(0);
4774 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004775 if (cur != ctxt->vstate->node)
4776 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004777 goto cont;
4778 }
4779 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004780 xmlNodePtr cur;
4781
4782 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004783 DEBUG_VALID_MSG("Failure, rollback");
4784 if (vstateVPop(ctxt) < 0 ) {
4785 DEBUG_VALID_MSG("exhaustion, failed");
4786 return(0);
4787 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004788 if (cur != ctxt->vstate->node)
4789 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004790 goto cont;
4791 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004792 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004793}
Daniel Veillard23e73572002-09-19 19:56:43 +00004794#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004795
4796/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00004797 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004798 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00004799 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004800 * @content: An element
4801 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4802 *
4803 * This will dump the list of elements to the buffer
4804 * Intended just for the debug routine
4805 */
4806static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00004807xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004808 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00004809 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004810
4811 if (node == NULL) return;
4812 if (glob) strcat(buf, "(");
4813 cur = node;
4814 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004815 len = strlen(buf);
4816 if (size - len < 50) {
4817 if ((size - len > 4) && (buf[len - 1] != '.'))
4818 strcat(buf, " ...");
4819 return;
4820 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004821 switch (cur->type) {
4822 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004823 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004824 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004825 if ((size - len > 4) && (buf[len - 1] != '.'))
4826 strcat(buf, " ...");
4827 return;
4828 }
4829 strcat(buf, (char *) cur->ns->prefix);
4830 strcat(buf, ":");
4831 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004832 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004833 if ((size - len > 4) && (buf[len - 1] != '.'))
4834 strcat(buf, " ...");
4835 return;
4836 }
4837 strcat(buf, (char *) cur->name);
4838 if (cur->next != NULL)
4839 strcat(buf, " ");
4840 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004841 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004842 if (xmlIsBlankNode(cur))
4843 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004844 case XML_CDATA_SECTION_NODE:
4845 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004846 strcat(buf, "CDATA");
4847 if (cur->next != NULL)
4848 strcat(buf, " ");
4849 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004850 case XML_ATTRIBUTE_NODE:
4851 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004852#ifdef LIBXML_DOCB_ENABLED
4853 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004854#endif
4855 case XML_HTML_DOCUMENT_NODE:
4856 case XML_DOCUMENT_TYPE_NODE:
4857 case XML_DOCUMENT_FRAG_NODE:
4858 case XML_NOTATION_NODE:
4859 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004860 strcat(buf, "???");
4861 if (cur->next != NULL)
4862 strcat(buf, " ");
4863 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004864 case XML_ENTITY_NODE:
4865 case XML_PI_NODE:
4866 case XML_DTD_NODE:
4867 case XML_COMMENT_NODE:
4868 case XML_ELEMENT_DECL:
4869 case XML_ATTRIBUTE_DECL:
4870 case XML_ENTITY_DECL:
4871 case XML_XINCLUDE_START:
4872 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004873 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004874 }
4875 cur = cur->next;
4876 }
4877 if (glob) strcat(buf, ")");
4878}
4879
4880/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004881 * xmlValidateElementContent:
4882 * @ctxt: the validation context
4883 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004884 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004885 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004886 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004887 *
4888 * Try to validate the content model of an element
4889 *
4890 * returns 1 if valid or 0 if not and -1 in case of error
4891 */
4892
4893static int
4894xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004895 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004896 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00004897#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00004898 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00004899#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00004900 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004901 xmlElementContentPtr cont;
4902 const xmlChar *name;
4903
4904 if (elemDecl == NULL)
4905 return(-1);
4906 cont = elemDecl->content;
4907 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004908
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004909#ifdef LIBXML_REGEXP_ENABLED
4910 /* Build the regexp associated to the content model */
4911 if (elemDecl->contModel == NULL)
4912 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4913 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004914 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004915 } else {
4916 xmlRegExecCtxtPtr exec;
4917
Daniel Veillardec498e12003-02-05 11:01:50 +00004918 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
4919 return(-1);
4920 }
Daniel Veillard01992e02002-10-09 10:20:30 +00004921 ctxt->nodeMax = 0;
4922 ctxt->nodeNr = 0;
4923 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004924 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4925 if (exec != NULL) {
4926 cur = child;
4927 while (cur != NULL) {
4928 switch (cur->type) {
4929 case XML_ENTITY_REF_NODE:
4930 /*
4931 * Push the current node to be able to roll back
4932 * and process within the entity
4933 */
4934 if ((cur->children != NULL) &&
4935 (cur->children->children != NULL)) {
4936 nodeVPush(ctxt, cur);
4937 cur = cur->children->children;
4938 continue;
4939 }
4940 break;
4941 case XML_TEXT_NODE:
4942 if (xmlIsBlankNode(cur))
4943 break;
4944 ret = 0;
4945 goto fail;
4946 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00004947 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004948 ret = 0;
4949 goto fail;
4950 case XML_ELEMENT_NODE:
4951 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004952 xmlChar fn[50];
4953 xmlChar *fullname;
4954
4955 fullname = xmlBuildQName(cur->name,
4956 cur->ns->prefix, fn, 50);
4957 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004958 ret = -1;
4959 goto fail;
4960 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004961 ret = xmlRegExecPushString(exec, fullname, NULL);
4962 if ((fullname != fn) && (fullname != cur->name))
4963 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004964 } else {
4965 ret = xmlRegExecPushString(exec, cur->name, NULL);
4966 }
4967 break;
4968 default:
4969 break;
4970 }
4971 /*
4972 * Switch to next element
4973 */
4974 cur = cur->next;
4975 while (cur == NULL) {
4976 cur = nodeVPop(ctxt);
4977 if (cur == NULL)
4978 break;
4979 cur = cur->next;
4980 }
4981 }
4982 ret = xmlRegExecPushString(exec, NULL, NULL);
4983fail:
4984 xmlRegFreeExecCtxt(exec);
4985 }
4986 }
4987#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004988 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004989 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004990 */
4991 ctxt->vstateMax = 8;
4992 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
4993 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
4994 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004995 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004996 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004997 }
4998 /*
4999 * The first entry in the stack is reserved to the current state
5000 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005001 ctxt->nodeMax = 0;
5002 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005003 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005004 ctxt->vstate = &ctxt->vstateTab[0];
5005 ctxt->vstateNr = 1;
5006 CONT = cont;
5007 NODE = child;
5008 DEPTH = 0;
5009 OCCURS = 0;
5010 STATE = 0;
5011 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005012 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005013 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5014 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005015 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005016 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005017 /*
5018 * An entities reference appeared at this level.
5019 * Buid a minimal representation of this node content
5020 * sufficient to run the validation process on it
5021 */
5022 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005023 cur = child;
5024 while (cur != NULL) {
5025 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005026 case XML_ENTITY_REF_NODE:
5027 /*
5028 * Push the current node to be able to roll back
5029 * and process within the entity
5030 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005031 if ((cur->children != NULL) &&
5032 (cur->children->children != NULL)) {
5033 nodeVPush(ctxt, cur);
5034 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005035 continue;
5036 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005037 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005038 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005039 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005040 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005041 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005042 case XML_CDATA_SECTION_NODE:
5043 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005044 case XML_ELEMENT_NODE:
5045 /*
5046 * Allocate a new node and minimally fills in
5047 * what's required
5048 */
5049 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5050 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005051 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005052 xmlFreeNodeList(repl);
5053 ret = -1;
5054 goto done;
5055 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005056 tmp->type = cur->type;
5057 tmp->name = cur->name;
5058 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005059 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005060 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005061 if (repl == NULL)
5062 repl = last = tmp;
5063 else {
5064 last->next = tmp;
5065 last = tmp;
5066 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005067 if (cur->type == XML_CDATA_SECTION_NODE) {
5068 /*
5069 * E59 spaces in CDATA does not match the
5070 * nonterminal S
5071 */
5072 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5073 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005074 break;
5075 default:
5076 break;
5077 }
5078 /*
5079 * Switch to next element
5080 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005081 cur = cur->next;
5082 while (cur == NULL) {
5083 cur = nodeVPop(ctxt);
5084 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005085 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005086 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005087 }
5088 }
5089
5090 /*
5091 * Relaunch the validation
5092 */
5093 ctxt->vstate = &ctxt->vstateTab[0];
5094 ctxt->vstateNr = 1;
5095 CONT = cont;
5096 NODE = repl;
5097 DEPTH = 0;
5098 OCCURS = 0;
5099 STATE = 0;
5100 ret = xmlValidateElementType(ctxt);
5101 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005102#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005103 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005104 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5105 char expr[5000];
5106 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005107
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005108 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005109 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005110 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005111#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005112 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005113 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005114 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005115#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005116 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005117
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005118 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005119 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5120 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5121 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005122 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005123 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5124 "Element content does not follow the DTD, expecting %s, got %s\n",
5125 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005126 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005127 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005128 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005129 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005130 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005131 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005132 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005133 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5134 "Element content does not follow the DTD\n",
5135 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005136 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005137 }
5138 ret = 0;
5139 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005140 if (ret == -3)
5141 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005142
Daniel Veillard23e73572002-09-19 19:56:43 +00005143#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005144done:
5145 /*
5146 * Deallocate the copy if done, and free up the validation stack
5147 */
5148 while (repl != NULL) {
5149 tmp = repl->next;
5150 xmlFree(repl);
5151 repl = tmp;
5152 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005153 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005154 if (ctxt->vstateTab != NULL) {
5155 xmlFree(ctxt->vstateTab);
5156 ctxt->vstateTab = NULL;
5157 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005158#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005159 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005160 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005161 if (ctxt->nodeTab != NULL) {
5162 xmlFree(ctxt->nodeTab);
5163 ctxt->nodeTab = NULL;
5164 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005165 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005166
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005167}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005168
Owen Taylor3473f882001-02-23 17:55:21 +00005169/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005170 * xmlValidateCdataElement:
5171 * @ctxt: the validation context
5172 * @doc: a document instance
5173 * @elem: an element instance
5174 *
5175 * Check that an element follows #CDATA
5176 *
5177 * returns 1 if valid or 0 otherwise
5178 */
5179static int
5180xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5181 xmlNodePtr elem) {
5182 int ret = 1;
5183 xmlNodePtr cur, child;
5184
Daniel Veillardceb09b92002-10-04 11:46:37 +00005185 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005186 return(0);
5187
5188 child = elem->children;
5189
5190 cur = child;
5191 while (cur != NULL) {
5192 switch (cur->type) {
5193 case XML_ENTITY_REF_NODE:
5194 /*
5195 * Push the current node to be able to roll back
5196 * and process within the entity
5197 */
5198 if ((cur->children != NULL) &&
5199 (cur->children->children != NULL)) {
5200 nodeVPush(ctxt, cur);
5201 cur = cur->children->children;
5202 continue;
5203 }
5204 break;
5205 case XML_COMMENT_NODE:
5206 case XML_PI_NODE:
5207 case XML_TEXT_NODE:
5208 case XML_CDATA_SECTION_NODE:
5209 break;
5210 default:
5211 ret = 0;
5212 goto done;
5213 }
5214 /*
5215 * Switch to next element
5216 */
5217 cur = cur->next;
5218 while (cur == NULL) {
5219 cur = nodeVPop(ctxt);
5220 if (cur == NULL)
5221 break;
5222 cur = cur->next;
5223 }
5224 }
5225done:
5226 ctxt->nodeMax = 0;
5227 ctxt->nodeNr = 0;
5228 if (ctxt->nodeTab != NULL) {
5229 xmlFree(ctxt->nodeTab);
5230 ctxt->nodeTab = NULL;
5231 }
5232 return(ret);
5233}
5234
5235/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005236 * xmlValidateCheckMixed:
5237 * @ctxt: the validation context
5238 * @cont: the mixed content model
5239 * @qname: the qualified name as appearing in the serialization
5240 *
5241 * Check if the given node is part of the content model.
5242 *
5243 * Returns 1 if yes, 0 if no, -1 in case of error
5244 */
5245static int
5246xmlValidateCheckMixed(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
5247 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005248 const xmlChar *name;
5249 int plen;
5250 name = xmlSplitQName3(qname, &plen);
5251
5252 if (name == NULL) {
5253 while (cont != NULL) {
5254 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5255 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5256 return(1);
5257 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5258 (cont->c1 != NULL) &&
5259 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5260 if ((cont->c1->prefix == NULL) &&
5261 (xmlStrEqual(cont->c1->name, qname)))
5262 return(1);
5263 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5264 (cont->c1 == NULL) ||
5265 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005266 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5267 "Internal: MIXED struct corrupted\n",
5268 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005269 break;
5270 }
5271 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005272 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005273 } else {
5274 while (cont != NULL) {
5275 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5276 if ((cont->prefix != NULL) &&
5277 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5278 (xmlStrEqual(cont->name, name)))
5279 return(1);
5280 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5281 (cont->c1 != NULL) &&
5282 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5283 if ((cont->c1->prefix != NULL) &&
5284 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5285 (xmlStrEqual(cont->c1->name, name)))
5286 return(1);
5287 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5288 (cont->c1 == NULL) ||
5289 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005290 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5291 "Internal: MIXED struct corrupted\n",
5292 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005293 break;
5294 }
5295 cont = cont->c2;
5296 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005297 }
5298 return(0);
5299}
5300
5301/**
5302 * xmlValidGetElemDecl:
5303 * @ctxt: the validation context
5304 * @doc: a document instance
5305 * @elem: an element instance
5306 * @extsubset: pointer, (out) indicate if the declaration was found
5307 * in the external subset.
5308 *
5309 * Finds a declaration associated to an element in the document.
5310 *
5311 * returns the pointer to the declaration or NULL if not found.
5312 */
5313static xmlElementPtr
5314xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5315 xmlNodePtr elem, int *extsubset) {
5316 xmlElementPtr elemDecl = NULL;
5317 const xmlChar *prefix = NULL;
5318
5319 if ((elem == NULL) || (elem->name == NULL)) return(NULL);
5320 if (extsubset != NULL)
5321 *extsubset = 0;
5322
5323 /*
5324 * Fetch the declaration for the qualified name
5325 */
5326 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5327 prefix = elem->ns->prefix;
5328
5329 if (prefix != NULL) {
5330 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5331 elem->name, prefix);
5332 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5333 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5334 elem->name, prefix);
5335 if ((elemDecl != NULL) && (extsubset != NULL))
5336 *extsubset = 1;
5337 }
5338 }
5339
5340 /*
5341 * Fetch the declaration for the non qualified name
5342 * This is "non-strict" validation should be done on the
5343 * full QName but in that case being flexible makes sense.
5344 */
5345 if (elemDecl == NULL) {
5346 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5347 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5348 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5349 if ((elemDecl != NULL) && (extsubset != NULL))
5350 *extsubset = 1;
5351 }
5352 }
5353 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005354 xmlErrValidNode(ctxt, elem,
5355 XML_DTD_UNKNOWN_ELEM,
5356 "No declaration for element %s\n",
5357 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005358 }
5359 return(elemDecl);
5360}
5361
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005362#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005363/**
5364 * xmlValidatePushElement:
5365 * @ctxt: the validation context
5366 * @doc: a document instance
5367 * @elem: an element instance
5368 * @qname: the qualified name as appearing in the serialization
5369 *
5370 * Push a new element start on the validation stack.
5371 *
5372 * returns 1 if no validation problem was found or 0 otherwise
5373 */
5374int
5375xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5376 xmlNodePtr elem, const xmlChar *qname) {
5377 int ret = 1;
5378 xmlElementPtr eDecl;
5379 int extsubset = 0;
5380
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005381/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005382 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5383 xmlValidStatePtr state = ctxt->vstate;
5384 xmlElementPtr elemDecl;
5385
5386 /*
5387 * Check the new element agaisnt the content model of the new elem.
5388 */
5389 if (state->elemDecl != NULL) {
5390 elemDecl = state->elemDecl;
5391
5392 switch(elemDecl->etype) {
5393 case XML_ELEMENT_TYPE_UNDEFINED:
5394 ret = 0;
5395 break;
5396 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005397 xmlErrValidNode(ctxt, state->node,
5398 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005399 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005400 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005401 ret = 0;
5402 break;
5403 case XML_ELEMENT_TYPE_ANY:
5404 /* I don't think anything is required then */
5405 break;
5406 case XML_ELEMENT_TYPE_MIXED:
5407 /* simple case of declared as #PCDATA */
5408 if ((elemDecl->content != NULL) &&
5409 (elemDecl->content->type ==
5410 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005411 xmlErrValidNode(ctxt, state->node,
5412 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005413 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005414 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005415 ret = 0;
5416 } else {
5417 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5418 qname);
5419 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005420 xmlErrValidNode(ctxt, state->node,
5421 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005422 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005423 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005424 }
5425 }
5426 break;
5427 case XML_ELEMENT_TYPE_ELEMENT:
5428 /*
5429 * TODO:
5430 * VC: Standalone Document Declaration
5431 * - element types with element content, if white space
5432 * occurs directly within any instance of those types.
5433 */
5434 if (state->exec != NULL) {
5435 ret = xmlRegExecPushString(state->exec, qname, NULL);
5436 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005437 xmlErrValidNode(ctxt, state->node,
5438 XML_DTD_CONTENT_MODEL,
5439 "Element %s content does not follow the DTD, Misplaced %s\n",
5440 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005441 ret = 0;
5442 } else {
5443 ret = 1;
5444 }
5445 }
5446 break;
5447 }
5448 }
5449 }
5450 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5451 vstateVPush(ctxt, eDecl, elem);
5452 return(ret);
5453}
5454
5455/**
5456 * xmlValidatePushCData:
5457 * @ctxt: the validation context
5458 * @data: some character data read
5459 * @len: the lenght of the data
5460 *
5461 * check the CData parsed for validation in the current stack
5462 *
5463 * returns 1 if no validation problem was found or 0 otherwise
5464 */
5465int
5466xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5467 int ret = 1;
5468
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005469/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005470 if (len <= 0)
5471 return(ret);
5472 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5473 xmlValidStatePtr state = ctxt->vstate;
5474 xmlElementPtr elemDecl;
5475
5476 /*
5477 * Check the new element agaisnt the content model of the new elem.
5478 */
5479 if (state->elemDecl != NULL) {
5480 elemDecl = state->elemDecl;
5481
5482 switch(elemDecl->etype) {
5483 case XML_ELEMENT_TYPE_UNDEFINED:
5484 ret = 0;
5485 break;
5486 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005487 xmlErrValidNode(ctxt, state->node,
5488 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005489 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005490 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005491 ret = 0;
5492 break;
5493 case XML_ELEMENT_TYPE_ANY:
5494 break;
5495 case XML_ELEMENT_TYPE_MIXED:
5496 break;
5497 case XML_ELEMENT_TYPE_ELEMENT:
5498 if (len > 0) {
5499 int i;
5500
5501 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005502 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005503 xmlErrValidNode(ctxt, state->node,
5504 XML_DTD_CONTENT_MODEL,
5505 "Element %s content does not follow the DTD, Text not allowed\n",
5506 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005507 ret = 0;
5508 goto done;
5509 }
5510 }
5511 /*
5512 * TODO:
5513 * VC: Standalone Document Declaration
5514 * element types with element content, if white space
5515 * occurs directly within any instance of those types.
5516 */
5517 }
5518 break;
5519 }
5520 }
5521 }
5522done:
5523 return(ret);
5524}
5525
5526/**
5527 * xmlValidatePopElement:
5528 * @ctxt: the validation context
5529 * @doc: a document instance
5530 * @elem: an element instance
5531 * @qname: the qualified name as appearing in the serialization
5532 *
5533 * Pop the element end from the validation stack.
5534 *
5535 * returns 1 if no validation problem was found or 0 otherwise
5536 */
5537int
5538xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005539 xmlNodePtr elem ATTRIBUTE_UNUSED,
5540 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005541 int ret = 1;
5542
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005543/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005544 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5545 xmlValidStatePtr state = ctxt->vstate;
5546 xmlElementPtr elemDecl;
5547
5548 /*
5549 * Check the new element agaisnt the content model of the new elem.
5550 */
5551 if (state->elemDecl != NULL) {
5552 elemDecl = state->elemDecl;
5553
5554 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5555 if (state->exec != NULL) {
5556 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5557 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005558 xmlErrValidNode(ctxt, state->node,
5559 XML_DTD_CONTENT_MODEL,
5560 "Element %s content does not follow the DTD, Expecting more child\n",
5561 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005562 } else {
5563 /*
5564 * previous validation errors should not generate
5565 * a new one here
5566 */
5567 ret = 1;
5568 }
5569 }
5570 }
5571 }
5572 vstateVPop(ctxt);
5573 }
5574 return(ret);
5575}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005576#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005577
5578/**
Owen Taylor3473f882001-02-23 17:55:21 +00005579 * xmlValidateOneElement:
5580 * @ctxt: the validation context
5581 * @doc: a document instance
5582 * @elem: an element instance
5583 *
5584 * Try to validate a single element and it's attributes,
5585 * basically it does the following checks as described by the
5586 * XML-1.0 recommendation:
5587 * - [ VC: Element Valid ]
5588 * - [ VC: Required Attribute ]
5589 * Then call xmlValidateOneAttribute() for each attribute present.
5590 *
5591 * The ID/IDREF checkings are done separately
5592 *
5593 * returns 1 if valid or 0 otherwise
5594 */
5595
5596int
5597xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5598 xmlNodePtr elem) {
5599 xmlElementPtr elemDecl = NULL;
5600 xmlElementContentPtr cont;
5601 xmlAttributePtr attr;
5602 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005603 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005604 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005605 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005606
5607 CHECK_DTD;
5608
5609 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005610 switch (elem->type) {
5611 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005612 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5613 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005614 return(0);
5615 case XML_TEXT_NODE:
5616 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005617 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5618 "Text element has children !\n",
5619 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005620 return(0);
5621 }
5622 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005623 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5624 "Text element has attribute !\n",
5625 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005626 return(0);
5627 }
5628 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005629 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5630 "Text element has namespace !\n",
5631 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005632 return(0);
5633 }
5634 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005635 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5636 "Text element has namespace !\n",
5637 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005638 return(0);
5639 }
5640 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005641 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5642 "Text element has no content !\n",
5643 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005644 return(0);
5645 }
5646 return(1);
5647 case XML_XINCLUDE_START:
5648 case XML_XINCLUDE_END:
5649 return(1);
5650 case XML_CDATA_SECTION_NODE:
5651 case XML_ENTITY_REF_NODE:
5652 case XML_PI_NODE:
5653 case XML_COMMENT_NODE:
5654 return(1);
5655 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005656 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5657 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005658 return(0);
5659 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005660 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5661 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005662 return(0);
5663 case XML_DOCUMENT_NODE:
5664 case XML_DOCUMENT_TYPE_NODE:
5665 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005666 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5667 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005668 return(0);
5669 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005670 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5671 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005672 return(0);
5673 case XML_ELEMENT_NODE:
5674 break;
5675 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005676 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5677 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005678 return(0);
5679 }
Owen Taylor3473f882001-02-23 17:55:21 +00005680
5681 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005682 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005683 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005684 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5685 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005686 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005687
Daniel Veillardea7751d2002-12-20 00:16:24 +00005688 /*
5689 * If vstateNr is not zero that means continuous validation is
5690 * activated, do not try to check the content model at that level.
5691 */
5692 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005693 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005694 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005695 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005696 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5697 "No declaration for element %s\n",
5698 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005699 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005700 case XML_ELEMENT_TYPE_EMPTY:
5701 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005702 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005703 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005704 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005705 ret = 0;
5706 }
5707 break;
5708 case XML_ELEMENT_TYPE_ANY:
5709 /* I don't think anything is required then */
5710 break;
5711 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005712
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005713 /* simple case of declared as #PCDATA */
5714 if ((elemDecl->content != NULL) &&
5715 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5716 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5717 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005718 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005719 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005720 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005721 }
5722 break;
5723 }
Owen Taylor3473f882001-02-23 17:55:21 +00005724 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005725 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005726 while (child != NULL) {
5727 if (child->type == XML_ELEMENT_NODE) {
5728 name = child->name;
5729 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005730 xmlChar fn[50];
5731 xmlChar *fullname;
5732
5733 fullname = xmlBuildQName(child->name, child->ns->prefix,
5734 fn, 50);
5735 if (fullname == NULL)
5736 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005737 cont = elemDecl->content;
5738 while (cont != NULL) {
5739 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005740 if (xmlStrEqual(cont->name, fullname))
5741 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005742 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5743 (cont->c1 != NULL) &&
5744 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005745 if (xmlStrEqual(cont->c1->name, fullname))
5746 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005747 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5748 (cont->c1 == NULL) ||
5749 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005750 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5751 "Internal: MIXED struct corrupted\n",
5752 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005753 break;
5754 }
5755 cont = cont->c2;
5756 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005757 if ((fullname != fn) && (fullname != child->name))
5758 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005759 if (cont != NULL)
5760 goto child_ok;
5761 }
5762 cont = elemDecl->content;
5763 while (cont != NULL) {
5764 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5765 if (xmlStrEqual(cont->name, name)) break;
5766 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5767 (cont->c1 != NULL) &&
5768 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5769 if (xmlStrEqual(cont->c1->name, name)) break;
5770 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5771 (cont->c1 == NULL) ||
5772 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005773 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5774 "Internal: MIXED struct corrupted\n",
5775 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005776 break;
5777 }
5778 cont = cont->c2;
5779 }
5780 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005781 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00005782 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005783 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005784 ret = 0;
5785 }
5786 }
5787child_ok:
5788 child = child->next;
5789 }
5790 break;
5791 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005792 if ((doc->standalone == 1) && (extsubset == 1)) {
5793 /*
5794 * VC: Standalone Document Declaration
5795 * - element types with element content, if white space
5796 * occurs directly within any instance of those types.
5797 */
5798 child = elem->children;
5799 while (child != NULL) {
5800 if (child->type == XML_TEXT_NODE) {
5801 const xmlChar *content = child->content;
5802
William M. Brack76e95df2003-10-18 16:20:14 +00005803 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005804 content++;
5805 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005806 xmlErrValidNode(ctxt, elem,
5807 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005808"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005809 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005810 ret = 0;
5811 break;
5812 }
5813 }
5814 child =child->next;
5815 }
5816 }
Owen Taylor3473f882001-02-23 17:55:21 +00005817 child = elem->children;
5818 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005819 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005820 if (tmp <= 0)
5821 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005822 break;
5823 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005824 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00005825
5826 /* [ VC: Required Attribute ] */
5827 attr = elemDecl->attributes;
5828 while (attr != NULL) {
5829 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005830 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005831
Daniel Veillarde4301c82002-02-13 13:32:35 +00005832 if ((attr->prefix == NULL) &&
5833 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5834 xmlNsPtr ns;
5835
5836 ns = elem->nsDef;
5837 while (ns != NULL) {
5838 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005839 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005840 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00005841 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005842 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5843 xmlNsPtr ns;
5844
5845 ns = elem->nsDef;
5846 while (ns != NULL) {
5847 if (xmlStrEqual(attr->name, ns->prefix))
5848 goto found;
5849 ns = ns->next;
5850 }
5851 } else {
5852 xmlAttrPtr attrib;
5853
5854 attrib = elem->properties;
5855 while (attrib != NULL) {
5856 if (xmlStrEqual(attrib->name, attr->name)) {
5857 if (attr->prefix != NULL) {
5858 xmlNsPtr nameSpace = attrib->ns;
5859
5860 if (nameSpace == NULL)
5861 nameSpace = elem->ns;
5862 /*
5863 * qualified names handling is problematic, having a
5864 * different prefix should be possible but DTDs don't
5865 * allow to define the URI instead of the prefix :-(
5866 */
5867 if (nameSpace == NULL) {
5868 if (qualified < 0)
5869 qualified = 0;
5870 } else if (!xmlStrEqual(nameSpace->prefix,
5871 attr->prefix)) {
5872 if (qualified < 1)
5873 qualified = 1;
5874 } else
5875 goto found;
5876 } else {
5877 /*
5878 * We should allow applications to define namespaces
5879 * for their application even if the DTD doesn't
5880 * carry one, otherwise, basically we would always
5881 * break.
5882 */
5883 goto found;
5884 }
5885 }
5886 attrib = attrib->next;
5887 }
Owen Taylor3473f882001-02-23 17:55:21 +00005888 }
5889 if (qualified == -1) {
5890 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005891 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005892 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005893 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005894 ret = 0;
5895 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005896 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005897 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005898 elem->name, attr->prefix,attr->name);
5899 ret = 0;
5900 }
5901 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005902 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005903 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005904 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005905 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005906 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005907 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005908 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005909 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005910 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5911 /*
5912 * Special tests checking #FIXED namespace declarations
5913 * have the right value since this is not done as an
5914 * attribute checking
5915 */
5916 if ((attr->prefix == NULL) &&
5917 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5918 xmlNsPtr ns;
5919
5920 ns = elem->nsDef;
5921 while (ns != NULL) {
5922 if (ns->prefix == NULL) {
5923 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005924 xmlErrValidNode(ctxt, elem,
5925 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00005926 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005927 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005928 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005929 }
5930 goto found;
5931 }
5932 ns = ns->next;
5933 }
5934 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5935 xmlNsPtr ns;
5936
5937 ns = elem->nsDef;
5938 while (ns != NULL) {
5939 if (xmlStrEqual(attr->name, ns->prefix)) {
5940 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005941 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005942 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005943 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005944 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005945 }
5946 goto found;
5947 }
5948 ns = ns->next;
5949 }
5950 }
Owen Taylor3473f882001-02-23 17:55:21 +00005951 }
5952found:
5953 attr = attr->nexth;
5954 }
5955 return(ret);
5956}
5957
5958/**
5959 * xmlValidateRoot:
5960 * @ctxt: the validation context
5961 * @doc: a document instance
5962 *
5963 * Try to validate a the root element
5964 * basically it does the following check as described by the
5965 * XML-1.0 recommendation:
5966 * - [ VC: Root Element Type ]
5967 * it doesn't try to recurse or apply other check to the element
5968 *
5969 * returns 1 if valid or 0 otherwise
5970 */
5971
5972int
5973xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
5974 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00005975 int ret;
5976
Owen Taylor3473f882001-02-23 17:55:21 +00005977 if (doc == NULL) return(0);
5978
5979 root = xmlDocGetRootElement(doc);
5980 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005981 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
5982 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005983 return(0);
5984 }
5985
5986 /*
5987 * When doing post validation against a separate DTD, those may
5988 * no internal subset has been generated
5989 */
5990 if ((doc->intSubset != NULL) &&
5991 (doc->intSubset->name != NULL)) {
5992 /*
5993 * Check first the document root against the NQName
5994 */
5995 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
5996 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005997 xmlChar fn[50];
5998 xmlChar *fullname;
5999
6000 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6001 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006002 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006003 return(0);
6004 }
6005 ret = xmlStrEqual(doc->intSubset->name, fullname);
6006 if ((fullname != fn) && (fullname != root->name))
6007 xmlFree(fullname);
6008 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006009 goto name_ok;
6010 }
6011 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6012 (xmlStrEqual(root->name, BAD_CAST "html")))
6013 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006014 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6015 "root and DTD name do not match '%s' and '%s'\n",
6016 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006017 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006018 }
6019 }
6020name_ok:
6021 return(1);
6022}
6023
6024
6025/**
6026 * xmlValidateElement:
6027 * @ctxt: the validation context
6028 * @doc: a document instance
6029 * @elem: an element instance
6030 *
6031 * Try to validate the subtree under an element
6032 *
6033 * returns 1 if valid or 0 otherwise
6034 */
6035
6036int
6037xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6038 xmlNodePtr child;
6039 xmlAttrPtr attr;
6040 xmlChar *value;
6041 int ret = 1;
6042
6043 if (elem == NULL) return(0);
6044
6045 /*
6046 * XInclude elements were added after parsing in the infoset,
6047 * they don't really mean anything validation wise.
6048 */
6049 if ((elem->type == XML_XINCLUDE_START) ||
6050 (elem->type == XML_XINCLUDE_END))
6051 return(1);
6052
6053 CHECK_DTD;
6054
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006055 /*
6056 * Entities references have to be handled separately
6057 */
6058 if (elem->type == XML_ENTITY_REF_NODE) {
6059 return(1);
6060 }
6061
Owen Taylor3473f882001-02-23 17:55:21 +00006062 ret &= xmlValidateOneElement(ctxt, doc, elem);
6063 attr = elem->properties;
6064 while(attr != NULL) {
6065 value = xmlNodeListGetString(doc, attr->children, 0);
6066 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6067 if (value != NULL)
6068 xmlFree(value);
6069 attr= attr->next;
6070 }
6071 child = elem->children;
6072 while (child != NULL) {
6073 ret &= xmlValidateElement(ctxt, doc, child);
6074 child = child->next;
6075 }
6076
6077 return(ret);
6078}
6079
Daniel Veillard8730c562001-02-26 10:49:57 +00006080/**
6081 * xmlValidateRef:
6082 * @ref: A reference to be validated
6083 * @ctxt: Validation context
6084 * @name: Name of ID we are searching for
6085 *
6086 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006087static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006088xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006089 const xmlChar *name) {
6090 xmlAttrPtr id;
6091 xmlAttrPtr attr;
6092
6093 if (ref == NULL)
6094 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006095 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006096 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006097 attr = ref->attr;
6098 if (attr == NULL) {
6099 xmlChar *dup, *str = NULL, *cur, save;
6100
6101 dup = xmlStrdup(name);
6102 if (dup == NULL) {
6103 ctxt->valid = 0;
6104 return;
6105 }
6106 cur = dup;
6107 while (*cur != 0) {
6108 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006109 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006110 save = *cur;
6111 *cur = 0;
6112 id = xmlGetID(ctxt->doc, str);
6113 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006114 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006115 "attribute %s line %d references an unknown ID \"%s\"\n",
6116 ref->name, ref->lineno, str);
6117 ctxt->valid = 0;
6118 }
6119 if (save == 0)
6120 break;
6121 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006122 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006123 }
6124 xmlFree(dup);
6125 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006126 id = xmlGetID(ctxt->doc, name);
6127 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006128 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006129 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006130 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006131 ctxt->valid = 0;
6132 }
6133 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6134 xmlChar *dup, *str = NULL, *cur, save;
6135
6136 dup = xmlStrdup(name);
6137 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006138 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006139 ctxt->valid = 0;
6140 return;
6141 }
6142 cur = dup;
6143 while (*cur != 0) {
6144 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006145 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006146 save = *cur;
6147 *cur = 0;
6148 id = xmlGetID(ctxt->doc, str);
6149 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006150 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006151 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006152 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006153 ctxt->valid = 0;
6154 }
6155 if (save == 0)
6156 break;
6157 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006158 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006159 }
6160 xmlFree(dup);
6161 }
6162}
6163
6164/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006165 * xmlWalkValidateList:
6166 * @data: Contents of current link
6167 * @user: Value supplied by the user
6168 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006169 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006170 */
6171static int
6172xmlWalkValidateList(const void *data, const void *user)
6173{
6174 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6175 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6176 return 1;
6177}
6178
6179/**
6180 * xmlValidateCheckRefCallback:
6181 * @ref_list: List of references
6182 * @ctxt: Validation context
6183 * @name: Name of ID we are searching for
6184 *
6185 */
6186static void
6187xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6188 const xmlChar *name) {
6189 xmlValidateMemo memo;
6190
6191 if (ref_list == NULL)
6192 return;
6193 memo.ctxt = ctxt;
6194 memo.name = name;
6195
6196 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6197
6198}
6199
6200/**
Owen Taylor3473f882001-02-23 17:55:21 +00006201 * xmlValidateDocumentFinal:
6202 * @ctxt: the validation context
6203 * @doc: a document instance
6204 *
6205 * Does the final step for the document validation once all the
6206 * incremental validation steps have been completed
6207 *
6208 * basically it does the following checks described by the XML Rec
6209 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006210 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006211 *
6212 * returns 1 if valid or 0 otherwise
6213 */
6214
6215int
6216xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6217 xmlRefTablePtr table;
6218
6219 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006220 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6221 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006222 return(0);
6223 }
6224
6225 /*
6226 * Check all the NOTATION/NOTATIONS attributes
6227 */
6228 /*
6229 * Check all the ENTITY/ENTITIES attributes definition for validity
6230 */
6231 /*
6232 * Check all the IDREF/IDREFS attributes definition for validity
6233 */
6234 table = (xmlRefTablePtr) doc->refs;
6235 ctxt->doc = doc;
6236 ctxt->valid = 1;
6237 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6238 return(ctxt->valid);
6239}
6240
6241/**
6242 * xmlValidateDtd:
6243 * @ctxt: the validation context
6244 * @doc: a document instance
6245 * @dtd: a dtd instance
6246 *
6247 * Try to validate the document against the dtd instance
6248 *
6249 * basically it does check all the definitions in the DtD.
6250 *
6251 * returns 1 if valid or 0 otherwise
6252 */
6253
6254int
6255xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6256 int ret;
6257 xmlDtdPtr oldExt;
6258 xmlNodePtr root;
6259
6260 if (dtd == NULL) return(0);
6261 if (doc == NULL) return(0);
6262 oldExt = doc->extSubset;
6263 doc->extSubset = dtd;
6264 ret = xmlValidateRoot(ctxt, doc);
6265 if (ret == 0) {
6266 doc->extSubset = oldExt;
6267 return(ret);
6268 }
6269 if (doc->ids != NULL) {
6270 xmlFreeIDTable(doc->ids);
6271 doc->ids = NULL;
6272 }
6273 if (doc->refs != NULL) {
6274 xmlFreeRefTable(doc->refs);
6275 doc->refs = NULL;
6276 }
6277 root = xmlDocGetRootElement(doc);
6278 ret = xmlValidateElement(ctxt, doc, root);
6279 ret &= xmlValidateDocumentFinal(ctxt, doc);
6280 doc->extSubset = oldExt;
6281 return(ret);
6282}
6283
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006284static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006285xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6286 const xmlChar *name ATTRIBUTE_UNUSED) {
6287 if (cur == NULL)
6288 return;
6289 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6290 xmlChar *notation = cur->content;
6291
Daniel Veillard878eab02002-02-19 13:46:09 +00006292 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006293 int ret;
6294
6295 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6296 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006297 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006298 }
6299 }
6300 }
6301}
6302
6303static void
Owen Taylor3473f882001-02-23 17:55:21 +00006304xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006305 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006306 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006307 xmlDocPtr doc;
6308 xmlElementPtr elem;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006309
Owen Taylor3473f882001-02-23 17:55:21 +00006310 if (cur == NULL)
6311 return;
6312 switch (cur->atype) {
6313 case XML_ATTRIBUTE_CDATA:
6314 case XML_ATTRIBUTE_ID:
6315 case XML_ATTRIBUTE_IDREF :
6316 case XML_ATTRIBUTE_IDREFS:
6317 case XML_ATTRIBUTE_NMTOKEN:
6318 case XML_ATTRIBUTE_NMTOKENS:
6319 case XML_ATTRIBUTE_ENUMERATION:
6320 break;
6321 case XML_ATTRIBUTE_ENTITY:
6322 case XML_ATTRIBUTE_ENTITIES:
6323 case XML_ATTRIBUTE_NOTATION:
6324 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006325
6326 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6327 cur->atype, cur->defaultValue);
6328 if ((ret == 0) && (ctxt->valid == 1))
6329 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006330 }
6331 if (cur->tree != NULL) {
6332 xmlEnumerationPtr tree = cur->tree;
6333 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006334 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006335 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006336 if ((ret == 0) && (ctxt->valid == 1))
6337 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006338 tree = tree->next;
6339 }
6340 }
6341 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006342 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6343 doc = cur->doc;
6344 if ((doc == NULL) || (cur->elem == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006345 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006346 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006347 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006348 return;
6349 }
6350 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6351 if (elem == NULL)
6352 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
6353 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006354 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006355 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006356 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006357 return;
6358 }
6359 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006360 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006361 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006362 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006363 ctxt->valid = 0;
6364 }
6365 }
Owen Taylor3473f882001-02-23 17:55:21 +00006366}
6367
6368/**
6369 * xmlValidateDtdFinal:
6370 * @ctxt: the validation context
6371 * @doc: a document instance
6372 *
6373 * Does the final step for the dtds validation once all the
6374 * subsets have been parsed
6375 *
6376 * basically it does the following checks described by the XML Rec
6377 * - check that ENTITY and ENTITIES type attributes default or
6378 * possible values matches one of the defined entities.
6379 * - check that NOTATION type attributes default or
6380 * possible values matches one of the defined notations.
6381 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006382 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006383 */
6384
6385int
6386xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006387 xmlDtdPtr dtd;
6388 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006389 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006390
6391 if (doc == NULL) return(0);
6392 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6393 return(0);
6394 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006395 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006396 dtd = doc->intSubset;
6397 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6398 table = (xmlAttributeTablePtr) dtd->attributes;
6399 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006400 }
6401 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006402 entities = (xmlEntitiesTablePtr) dtd->entities;
6403 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6404 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006405 }
6406 dtd = doc->extSubset;
6407 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6408 table = (xmlAttributeTablePtr) dtd->attributes;
6409 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006410 }
6411 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006412 entities = (xmlEntitiesTablePtr) dtd->entities;
6413 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6414 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006415 }
6416 return(ctxt->valid);
6417}
6418
6419/**
6420 * xmlValidateDocument:
6421 * @ctxt: the validation context
6422 * @doc: a document instance
6423 *
6424 * Try to validate the document instance
6425 *
6426 * basically it does the all the checks described by the XML Rec
6427 * i.e. validates the internal and external subset (if present)
6428 * and validate the document tree.
6429 *
6430 * returns 1 if valid or 0 otherwise
6431 */
6432
6433int
6434xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6435 int ret;
6436 xmlNodePtr root;
6437
Daniel Veillard2fd85422002-10-16 14:32:41 +00006438 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006439 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6440 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006441 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006442 }
Owen Taylor3473f882001-02-23 17:55:21 +00006443 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6444 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6445 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6446 doc->intSubset->SystemID);
6447 if (doc->extSubset == NULL) {
6448 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006449 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006450 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006451 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006452 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006453 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006454 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006455 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006456 }
6457 return(0);
6458 }
6459 }
6460
6461 if (doc->ids != NULL) {
6462 xmlFreeIDTable(doc->ids);
6463 doc->ids = NULL;
6464 }
6465 if (doc->refs != NULL) {
6466 xmlFreeRefTable(doc->refs);
6467 doc->refs = NULL;
6468 }
6469 ret = xmlValidateDtdFinal(ctxt, doc);
6470 if (!xmlValidateRoot(ctxt, doc)) return(0);
6471
6472 root = xmlDocGetRootElement(doc);
6473 ret &= xmlValidateElement(ctxt, doc, root);
6474 ret &= xmlValidateDocumentFinal(ctxt, doc);
6475 return(ret);
6476}
6477
Owen Taylor3473f882001-02-23 17:55:21 +00006478/************************************************************************
6479 * *
6480 * Routines for dynamic validation editing *
6481 * *
6482 ************************************************************************/
6483
6484/**
6485 * xmlValidGetPotentialChildren:
6486 * @ctree: an element content tree
6487 * @list: an array to store the list of child names
6488 * @len: a pointer to the number of element in the list
6489 * @max: the size of the array
6490 *
6491 * Build/extend a list of potential children allowed by the content tree
6492 *
6493 * returns the number of element in the list, or -1 in case of error.
6494 */
6495
6496int
6497xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6498 int *len, int max) {
6499 int i;
6500
6501 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6502 return(-1);
6503 if (*len >= max) return(*len);
6504
6505 switch (ctree->type) {
6506 case XML_ELEMENT_CONTENT_PCDATA:
6507 for (i = 0; i < *len;i++)
6508 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6509 list[(*len)++] = BAD_CAST "#PCDATA";
6510 break;
6511 case XML_ELEMENT_CONTENT_ELEMENT:
6512 for (i = 0; i < *len;i++)
6513 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6514 list[(*len)++] = ctree->name;
6515 break;
6516 case XML_ELEMENT_CONTENT_SEQ:
6517 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6518 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6519 break;
6520 case XML_ELEMENT_CONTENT_OR:
6521 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6522 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6523 break;
6524 }
6525
6526 return(*len);
6527}
6528
6529/**
6530 * xmlValidGetValidElements:
6531 * @prev: an element to insert after
6532 * @next: an element to insert next
6533 * @list: an array to store the list of child names
6534 * @max: the size of the array
6535 *
6536 * This function returns the list of authorized children to insert
6537 * within an existing tree while respecting the validity constraints
6538 * forced by the Dtd. The insertion point is defined using @prev and
6539 * @next in the following ways:
6540 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6541 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6542 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6543 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6544 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6545 *
6546 * pointers to the element names are inserted at the beginning of the array
6547 * and do not need to be freed.
6548 *
6549 * returns the number of element in the list, or -1 in case of error. If
6550 * the function returns the value @max the caller is invited to grow the
6551 * receiving array and retry.
6552 */
6553
6554int
6555xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
6556 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006557 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006558 int nb_valid_elements = 0;
6559 const xmlChar *elements[256];
6560 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006561 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006562
6563 xmlNode *ref_node;
6564 xmlNode *parent;
6565 xmlNode *test_node;
6566
6567 xmlNode *prev_next;
6568 xmlNode *next_prev;
6569 xmlNode *parent_childs;
6570 xmlNode *parent_last;
6571
6572 xmlElement *element_desc;
6573
Daniel Veillardbb4e46d2002-03-10 16:49:08 +00006574 memset(&vctxt, 0, sizeof (xmlValidCtxt));
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006575
Owen Taylor3473f882001-02-23 17:55:21 +00006576 if (prev == NULL && next == NULL)
6577 return(-1);
6578
6579 if (list == NULL) return(-1);
6580 if (max <= 0) return(-1);
6581
6582 nb_valid_elements = 0;
6583 ref_node = prev ? prev : next;
6584 parent = ref_node->parent;
6585
6586 /*
6587 * Retrieves the parent element declaration
6588 */
6589 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6590 parent->name);
6591 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6592 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6593 parent->name);
6594 if (element_desc == NULL) return(-1);
6595
6596 /*
6597 * Do a backup of the current tree structure
6598 */
6599 prev_next = prev ? prev->next : NULL;
6600 next_prev = next ? next->prev : NULL;
6601 parent_childs = parent->children;
6602 parent_last = parent->last;
6603
6604 /*
6605 * Creates a dummy node and insert it into the tree
6606 */
6607 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
6608 test_node->doc = ref_node->doc;
6609 test_node->parent = parent;
6610 test_node->prev = prev;
6611 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006612 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006613
6614 if (prev) prev->next = test_node;
6615 else parent->children = test_node;
6616
6617 if (next) next->prev = test_node;
6618 else parent->last = test_node;
6619
6620 /*
6621 * Insert each potential child node and check if the parent is
6622 * still valid
6623 */
6624 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6625 elements, &nb_elements, 256);
6626
6627 for (i = 0;i < nb_elements;i++) {
6628 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006629 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006630 int j;
6631
6632 for (j = 0; j < nb_valid_elements;j++)
6633 if (xmlStrEqual(elements[i], list[j])) break;
6634 list[nb_valid_elements++] = elements[i];
6635 if (nb_valid_elements >= max) break;
6636 }
6637 }
6638
6639 /*
6640 * Restore the tree structure
6641 */
6642 if (prev) prev->next = prev_next;
6643 if (next) next->prev = next_prev;
6644 parent->children = parent_childs;
6645 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006646
6647 /*
6648 * Free up the dummy node
6649 */
6650 test_node->name = name;
6651 xmlFreeNode(test_node);
6652
Owen Taylor3473f882001-02-23 17:55:21 +00006653 return(nb_valid_elements);
6654}
Daniel Veillard4432df22003-09-28 18:58:27 +00006655#endif /* LIBXML_VALID_ENABLED */
6656