blob: f8715320d963e2d04002d7ea8e4ace1f0a9d110b [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);
30#ifdef LIBXML_VALID_ENABLED
31
Daniel Veillarde62d36c2001-05-15 08:53:16 +000032/* #define DEBUG_VALID_ALGO */
Daniel Veillard5acfd6b2002-09-18 16:29:02 +000033/* #define DEBUG_REGEXP_ALGO */
Daniel Veillarde62d36c2001-05-15 08:53:16 +000034
Daniel Veillarda646cfd2002-09-17 21:50:03 +000035#define TODO \
36 xmlGenericError(xmlGenericErrorContext, \
37 "Unimplemented block at %s:%d\n", \
38 __FILE__, __LINE__);
Owen Taylor3473f882001-02-23 17:55:21 +000039
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000040/************************************************************************
41 * *
42 * Error handling routines *
43 * *
44 ************************************************************************/
45
Daniel Veillardea7751d2002-12-20 00:16:24 +000046#define VERROR \
47 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
Owen Taylor3473f882001-02-23 17:55:21 +000048
Daniel Veillardea7751d2002-12-20 00:16:24 +000049#define VWARNING \
50 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
51
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000052/**
53 * xmlErrMemory:
54 * @ctxt: an XML validation parser context
55 * @extra: extra informations
56 *
57 * Handle an out of memory error
58 */
59static void
60xmlErrMemory(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, const char *extra)
61{
62 if (extra)
63 xmlRaiseError(NULL, XML_FROM_DTD, XML_ERR_NO_MEMORY,
64 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
65 "Memory allocation failed : %s\n", extra);
66 else
67 xmlRaiseError(NULL, XML_FROM_DTD, XML_ERR_NO_MEMORY,
68 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
69 "Memory allocation failed\n");
70}
71
72/**
73 * xmlErrValid:
74 * @ctxt: an XML validation parser context
75 * @
76 * @extra: extra informations
77 *
78 * Handle a validation error
79 */
80static void
81xmlErrValid(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlParserErrors error,
82 const char *msg, const char *extra)
83{
84 if (extra)
85 xmlRaiseError(NULL, XML_FROM_DTD, error,
86 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
87 msg, extra);
88 else
89 xmlRaiseError(NULL, XML_FROM_DTD, error,
90 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
91 msg);
92}
93
Daniel Veillardea7751d2002-12-20 00:16:24 +000094
95#ifdef LIBXML_REGEXP_ENABLED
96/*
97 * If regexp are enabled we can do continuous validation without the
98 * need of a tree to validate the content model. this is done in each
99 * callbacks.
100 * Each xmlValidState represent the validation state associated to the
101 * set of nodes currently open from the document root to the current element.
102 */
103
104
105typedef struct _xmlValidState {
106 xmlElementPtr elemDecl; /* pointer to the content model */
107 xmlNodePtr node; /* pointer to the current node */
108 xmlRegExecCtxtPtr exec; /* regexp runtime */
109} _xmlValidState;
110
111
112static int
113vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000114 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000115 ctxt->vstateMax = 10;
116 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
117 sizeof(ctxt->vstateTab[0]));
118 if (ctxt->vstateTab == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000119 xmlErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000120 return(-1);
121 }
122 }
123
124 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000125 xmlValidState *tmp;
126
127 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
128 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
129 if (tmp == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000130 xmlErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000131 return(-1);
132 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000133 ctxt->vstateMax *= 2;
134 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000135 }
136 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
137 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
138 ctxt->vstateTab[ctxt->vstateNr].node = node;
139 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
140 if (elemDecl->contModel == NULL)
141 xmlValidBuildContentModel(ctxt, elemDecl);
142 if (elemDecl->contModel != NULL) {
143 ctxt->vstateTab[ctxt->vstateNr].exec =
144 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
145 } else {
146 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
147 VERROR(ctxt->userData,
148 "Failed to build content model regexp for %s", node->name);
149 }
150 }
151 return(ctxt->vstateNr++);
152}
153
154static int
155vstateVPop(xmlValidCtxtPtr ctxt) {
156 xmlElementPtr elemDecl;
157
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000158 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000159 ctxt->vstateNr--;
160 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
161 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
162 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
163 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
164 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
165 }
166 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
167 if (ctxt->vstateNr >= 1)
168 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
169 else
170 ctxt->vstate = NULL;
171 return(ctxt->vstateNr);
172}
173
174#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000175/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000176 * If regexp are not enabled, it uses a home made algorithm less
177 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000178 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000179 * only restriction is on the deepness of the tree limited by the
180 * size of the occurs bitfield
181 *
182 * this is the content of a saved state for rollbacks
183 */
184
185#define ROLLBACK_OR 0
186#define ROLLBACK_PARENT 1
187
Daniel Veillardb44025c2001-10-11 22:55:55 +0000188typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000189 xmlElementContentPtr cont; /* pointer to the content model subtree */
190 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000191 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000192 unsigned char depth; /* current depth in the overall tree */
193 unsigned char state; /* ROLLBACK_XXX */
194} _xmlValidState;
195
Daniel Veillardfc57b412002-04-29 15:50:14 +0000196#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000197#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
198#define CONT ctxt->vstate->cont
199#define NODE ctxt->vstate->node
200#define DEPTH ctxt->vstate->depth
201#define OCCURS ctxt->vstate->occurs
202#define STATE ctxt->vstate->state
203
Daniel Veillard5344c602001-12-31 16:37:34 +0000204#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
205#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000206
Daniel Veillard5344c602001-12-31 16:37:34 +0000207#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
208#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000209
210static int
211vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
212 xmlNodePtr node, unsigned char depth, long occurs,
213 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000214 int i = ctxt->vstateNr - 1;
215
Daniel Veillard940492d2002-04-15 10:15:25 +0000216 if (ctxt->vstateNr > MAX_RECURSE) {
217 return(-1);
218 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000219 if (ctxt->vstateTab == NULL) {
220 ctxt->vstateMax = 8;
221 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
222 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
223 if (ctxt->vstateTab == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000224 xmlErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000225 return(-1);
226 }
227 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000228 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000229 xmlValidState *tmp;
230
231 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
232 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
233 if (tmp == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000234 xmlErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000235 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000236 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000237 ctxt->vstateMax *= 2;
238 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000239 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000240 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000241 /*
242 * Don't push on the stack a state already here
243 */
244 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
245 (ctxt->vstateTab[i].node == node) &&
246 (ctxt->vstateTab[i].depth == depth) &&
247 (ctxt->vstateTab[i].occurs == occurs) &&
248 (ctxt->vstateTab[i].state == state))
249 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000250 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
251 ctxt->vstateTab[ctxt->vstateNr].node = node;
252 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
253 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
254 ctxt->vstateTab[ctxt->vstateNr].state = state;
255 return(ctxt->vstateNr++);
256}
257
258static int
259vstateVPop(xmlValidCtxtPtr ctxt) {
260 if (ctxt->vstateNr <= 1) return(-1);
261 ctxt->vstateNr--;
262 ctxt->vstate = &ctxt->vstateTab[0];
263 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
264 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
265 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
266 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
267 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
268 return(ctxt->vstateNr);
269}
270
Daniel Veillard118aed72002-09-24 14:13:13 +0000271#endif /* LIBXML_REGEXP_ENABLED */
272
Daniel Veillard1c732d22002-11-30 11:22:59 +0000273static int
274nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
275{
276 if (ctxt->nodeMax <= 0) {
277 ctxt->nodeMax = 4;
278 ctxt->nodeTab =
279 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
280 sizeof(ctxt->nodeTab[0]));
281 if (ctxt->nodeTab == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000282 xmlErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000283 ctxt->nodeMax = 0;
284 return (0);
285 }
286 }
287 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000288 xmlNodePtr *tmp;
289 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
290 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
291 if (tmp == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000292 xmlErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000293 return (0);
294 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000295 ctxt->nodeMax *= 2;
296 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000297 }
298 ctxt->nodeTab[ctxt->nodeNr] = value;
299 ctxt->node = value;
300 return (ctxt->nodeNr++);
301}
302static xmlNodePtr
303nodeVPop(xmlValidCtxtPtr ctxt)
304{
305 xmlNodePtr ret;
306
307 if (ctxt->nodeNr <= 0)
308 return (0);
309 ctxt->nodeNr--;
310 if (ctxt->nodeNr > 0)
311 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
312 else
313 ctxt->node = NULL;
314 ret = ctxt->nodeTab[ctxt->nodeNr];
315 ctxt->nodeTab[ctxt->nodeNr] = 0;
316 return (ret);
317}
Owen Taylor3473f882001-02-23 17:55:21 +0000318
Owen Taylor3473f882001-02-23 17:55:21 +0000319#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000320static void
321xmlValidPrintNode(xmlNodePtr cur) {
322 if (cur == NULL) {
323 xmlGenericError(xmlGenericErrorContext, "null");
324 return;
325 }
326 switch (cur->type) {
327 case XML_ELEMENT_NODE:
328 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
329 break;
330 case XML_TEXT_NODE:
331 xmlGenericError(xmlGenericErrorContext, "text ");
332 break;
333 case XML_CDATA_SECTION_NODE:
334 xmlGenericError(xmlGenericErrorContext, "cdata ");
335 break;
336 case XML_ENTITY_REF_NODE:
337 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
338 break;
339 case XML_PI_NODE:
340 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
341 break;
342 case XML_COMMENT_NODE:
343 xmlGenericError(xmlGenericErrorContext, "comment ");
344 break;
345 case XML_ATTRIBUTE_NODE:
346 xmlGenericError(xmlGenericErrorContext, "?attr? ");
347 break;
348 case XML_ENTITY_NODE:
349 xmlGenericError(xmlGenericErrorContext, "?ent? ");
350 break;
351 case XML_DOCUMENT_NODE:
352 xmlGenericError(xmlGenericErrorContext, "?doc? ");
353 break;
354 case XML_DOCUMENT_TYPE_NODE:
355 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
356 break;
357 case XML_DOCUMENT_FRAG_NODE:
358 xmlGenericError(xmlGenericErrorContext, "?frag? ");
359 break;
360 case XML_NOTATION_NODE:
361 xmlGenericError(xmlGenericErrorContext, "?nota? ");
362 break;
363 case XML_HTML_DOCUMENT_NODE:
364 xmlGenericError(xmlGenericErrorContext, "?html? ");
365 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000366#ifdef LIBXML_DOCB_ENABLED
367 case XML_DOCB_DOCUMENT_NODE:
368 xmlGenericError(xmlGenericErrorContext, "?docb? ");
369 break;
370#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000371 case XML_DTD_NODE:
372 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
373 break;
374 case XML_ELEMENT_DECL:
375 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
376 break;
377 case XML_ATTRIBUTE_DECL:
378 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
379 break;
380 case XML_ENTITY_DECL:
381 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
382 break;
383 case XML_NAMESPACE_DECL:
384 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
385 break;
386 case XML_XINCLUDE_START:
387 xmlGenericError(xmlGenericErrorContext, "incstart ");
388 break;
389 case XML_XINCLUDE_END:
390 xmlGenericError(xmlGenericErrorContext, "incend ");
391 break;
392 }
393}
394
395static void
396xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000397 if (cur == NULL)
398 xmlGenericError(xmlGenericErrorContext, "null ");
399 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000400 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000401 cur = cur->next;
402 }
403}
404
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000405static void
406xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000407 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000408
409 expr[0] = 0;
410 xmlGenericError(xmlGenericErrorContext, "valid: ");
411 xmlValidPrintNodeList(cur);
412 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000413 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000414 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
415}
416
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000417static void
418xmlValidDebugState(xmlValidStatePtr state) {
419 xmlGenericError(xmlGenericErrorContext, "(");
420 if (state->cont == NULL)
421 xmlGenericError(xmlGenericErrorContext, "null,");
422 else
423 switch (state->cont->type) {
424 case XML_ELEMENT_CONTENT_PCDATA:
425 xmlGenericError(xmlGenericErrorContext, "pcdata,");
426 break;
427 case XML_ELEMENT_CONTENT_ELEMENT:
428 xmlGenericError(xmlGenericErrorContext, "%s,",
429 state->cont->name);
430 break;
431 case XML_ELEMENT_CONTENT_SEQ:
432 xmlGenericError(xmlGenericErrorContext, "seq,");
433 break;
434 case XML_ELEMENT_CONTENT_OR:
435 xmlGenericError(xmlGenericErrorContext, "or,");
436 break;
437 }
438 xmlValidPrintNode(state->node);
439 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
440 state->depth, state->occurs, state->state);
441}
442
443static void
444xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
445 int i, j;
446
447 xmlGenericError(xmlGenericErrorContext, "state: ");
448 xmlValidDebugState(ctxt->vstate);
449 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
450 ctxt->vstateNr - 1);
451 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
452 xmlValidDebugState(&ctxt->vstateTab[j]);
453 xmlGenericError(xmlGenericErrorContext, "\n");
454}
455
456/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000457#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000458 *****/
459
460#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000461#define DEBUG_VALID_MSG(m) \
462 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
463
Owen Taylor3473f882001-02-23 17:55:21 +0000464#else
465#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000466#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000467#endif
468
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000469/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000470
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000471#define VECTXT(ctxt, node) \
472 if ((ctxt != NULL) && (ctxt->error != NULL) && \
Daniel Veillard76575762002-09-05 14:21:15 +0000473 (node != NULL)) { \
474 xmlChar *base = xmlNodeGetBase(NULL,node); \
475 if (base != NULL) { \
476 ctxt->error(ctxt->userData, "%s:%d: ", base, \
Daniel Veillard366a9152002-10-23 20:43:53 +0000477 (int) (long) node->content); \
Daniel Veillard76575762002-09-05 14:21:15 +0000478 xmlFree(base); \
479 } else \
480 ctxt->error(ctxt->userData, ":%d: ", \
Daniel Veillard366a9152002-10-23 20:43:53 +0000481 (int) (long) node->content); \
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000482 }
483
484#define VWCTXT(ctxt, node) \
485 if ((ctxt != NULL) && (ctxt->warning != NULL) && \
Daniel Veillard76575762002-09-05 14:21:15 +0000486 (node != NULL)) { \
487 xmlChar *base = xmlNodeGetBase(NULL,node); \
488 if (base != NULL) { \
489 ctxt->warning(ctxt->userData, "%s:%d: ", base, \
Daniel Veillard366a9152002-10-23 20:43:53 +0000490 (int) (long) node->content); \
Daniel Veillard76575762002-09-05 14:21:15 +0000491 xmlFree(base); \
492 } else \
493 ctxt->warning(ctxt->userData, ":%d: ", \
Daniel Veillard366a9152002-10-23 20:43:53 +0000494 (int) (long) node->content); \
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000495 }
496
Owen Taylor3473f882001-02-23 17:55:21 +0000497#define CHECK_DTD \
498 if (doc == NULL) return(0); \
499 else if ((doc->intSubset == NULL) && \
500 (doc->extSubset == NULL)) return(0)
501
Owen Taylor3473f882001-02-23 17:55:21 +0000502xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
503
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000504#ifdef LIBXML_REGEXP_ENABLED
505
506/************************************************************************
507 * *
508 * Content model validation based on the regexps *
509 * *
510 ************************************************************************/
511
512/**
513 * xmlValidBuildAContentModel:
514 * @content: the content model
515 * @ctxt: the schema parser context
516 * @name: the element name whose content is being built
517 *
518 * Generate the automata sequence needed for that type
519 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000520 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000521 */
522static int
523xmlValidBuildAContentModel(xmlElementContentPtr content,
524 xmlValidCtxtPtr ctxt,
525 const xmlChar *name) {
526 if (content == NULL) {
527 VERROR(ctxt->userData,
528 "Found unexpected type = NULL in %s content model\n", name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000529 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000530 }
531 switch (content->type) {
532 case XML_ELEMENT_CONTENT_PCDATA:
533 VERROR(ctxt->userData, "ContentModel found PCDATA for element %s\n",
534 name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000535 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000536 break;
537 case XML_ELEMENT_CONTENT_ELEMENT: {
538 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000539 xmlChar fn[50];
540 xmlChar *fullname;
541
542 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
543 if (fullname == NULL) {
544 VERROR(ctxt->userData, "Out of memory\n");
545 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000546 }
547
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000548 switch (content->ocur) {
549 case XML_ELEMENT_CONTENT_ONCE:
550 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000551 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000552 break;
553 case XML_ELEMENT_CONTENT_OPT:
554 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000555 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000556 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
557 break;
558 case XML_ELEMENT_CONTENT_PLUS:
559 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000560 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000561 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000562 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000563 break;
564 case XML_ELEMENT_CONTENT_MULT:
565 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000566 ctxt->state, fullname, NULL);
Daniel Veillard57e79b32003-02-04 15:33:12 +0000567 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
568 NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000569 break;
570 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000571 if ((fullname != fn) && (fullname != content->name))
572 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000573 break;
574 }
575 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000576 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000577 xmlElementContentOccur ocur;
578
579 /*
580 * Simply iterate over the content
581 */
582 oldstate = ctxt->state;
583 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000584 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
585 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
586 oldstate = ctxt->state;
587 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000588 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000589 xmlValidBuildAContentModel(content->c1, ctxt, name);
590 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000591 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
592 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
593 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000594 oldend = ctxt->state;
595 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000596 switch (ocur) {
597 case XML_ELEMENT_CONTENT_ONCE:
598 break;
599 case XML_ELEMENT_CONTENT_OPT:
600 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
601 break;
602 case XML_ELEMENT_CONTENT_MULT:
603 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000604 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000605 break;
606 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000607 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000608 break;
609 }
610 break;
611 }
612 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000613 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000614 xmlElementContentOccur ocur;
615
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000616 ocur = content->ocur;
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000617 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
618 (ocur == XML_ELEMENT_CONTENT_MULT)) {
619 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
620 ctxt->state, NULL);
621 }
622 oldstate = ctxt->state;
623 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000624
625 /*
626 * iterate over the subtypes and remerge the end with an
627 * epsilon transition
628 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000629 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000630 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000631 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000632 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000633 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000634 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
635 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000636 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000637 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000638 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
639 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000640 switch (ocur) {
641 case XML_ELEMENT_CONTENT_ONCE:
642 break;
643 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000644 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000645 break;
646 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000647 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
648 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000649 break;
650 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000651 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000652 break;
653 }
654 break;
655 }
656 default:
657 VERROR(ctxt->userData, "ContentModel broken for element %s\n",
658 name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000659 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000660 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000661 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000662}
663/**
664 * xmlValidBuildContentModel:
665 * @ctxt: a validation context
666 * @elem: an element declaration node
667 *
668 * (Re)Build the automata associated to the content model of this
669 * element
670 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000671 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000672 */
673int
674xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000675
676 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000677 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000678 if (elem->type != XML_ELEMENT_DECL)
679 return(0);
680 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
681 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000682 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000683 if (elem->contModel != NULL) {
684 if (!xmlRegexpIsDeterminist(elem->contModel)) {
685 ctxt->valid = 0;
686 return(0);
687 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000688 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000689 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000690
691 ctxt->am = xmlNewAutomata();
692 if (ctxt->am == NULL) {
693 VERROR(ctxt->userData, "Cannot create automata for element %s\n",
694 elem->name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000695 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000696 }
William M. Brack78637da2003-07-31 14:47:38 +0000697 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000698 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
699 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000700 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000701 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000702 char expr[5000];
703 expr[0] = 0;
704 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
705 VERROR(ctxt->userData, "Content model of %s is not determinist: %s\n",
706 elem->name, expr);
707#ifdef DEBUG_REGEXP_ALGO
708 xmlRegexpPrint(stderr, elem->contModel);
709#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000710 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000711 ctxt->state = NULL;
712 xmlFreeAutomata(ctxt->am);
713 ctxt->am = NULL;
714 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000715 }
716 ctxt->state = NULL;
717 xmlFreeAutomata(ctxt->am);
718 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000719 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000720}
721
722#endif /* LIBXML_REGEXP_ENABLED */
723
Owen Taylor3473f882001-02-23 17:55:21 +0000724/****************************************************************
725 * *
726 * Util functions for data allocation/deallocation *
727 * *
728 ****************************************************************/
729
730/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000731 * xmlNewValidCtxt:
732 *
733 * Allocate a validation context structure.
734 *
735 * Returns NULL if not, otherwise the new validation context structure
736 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000737xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000738 xmlValidCtxtPtr ret;
739
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000740 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
741 xmlErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000742 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000743 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000744
745 (void) memset(ret, 0, sizeof (xmlValidCtxt));
746
747 return (ret);
748}
749
750/**
751 * xmlFreeValidCtxt:
752 * @cur: the validation context to free
753 *
754 * Free a validation context structure.
755 */
756void
757xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
758 xmlFree(cur);
759}
760
Daniel Veillard4432df22003-09-28 18:58:27 +0000761#endif /* LIBXML_VALID_ENABLED */
762
Daniel Veillarda37aab82003-06-09 09:10:36 +0000763/**
Owen Taylor3473f882001-02-23 17:55:21 +0000764 * xmlNewElementContent:
765 * @name: the subelement name or NULL
766 * @type: the type of element content decl
767 *
768 * Allocate an element content structure.
769 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000770 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000771 */
772xmlElementContentPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000773xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000774 xmlElementContentPtr ret;
775
776 switch(type) {
777 case XML_ELEMENT_CONTENT_ELEMENT:
778 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000779 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
780 "xmlNewElementContent : name == NULL !\n",
781 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000782 }
783 break;
784 case XML_ELEMENT_CONTENT_PCDATA:
785 case XML_ELEMENT_CONTENT_SEQ:
786 case XML_ELEMENT_CONTENT_OR:
787 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000788 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
789 "xmlNewElementContent : name != NULL !\n",
790 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000791 }
792 break;
793 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000794 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
795 "Internal: ELEMENT content corrupted invalid type\n",
796 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000797 return(NULL);
798 }
799 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
800 if (ret == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000801 xmlErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000802 return(NULL);
803 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000804 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000805 ret->type = type;
806 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000807 if (name != NULL) {
808 xmlChar *prefix = NULL;
809 ret->name = xmlSplitQName2(name, &prefix);
810 if (ret->name == NULL)
811 ret->name = xmlStrdup(name);
812 ret->prefix = prefix;
813 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000814 ret->name = NULL;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000815 ret->prefix = NULL;
816 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000817 ret->c1 = ret->c2 = ret->parent = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000818 return(ret);
819}
820
821/**
822 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000823 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +0000824 *
825 * Build a copy of an element content description.
826 *
827 * Returns the new xmlElementContentPtr or NULL in case of error.
828 */
829xmlElementContentPtr
830xmlCopyElementContent(xmlElementContentPtr cur) {
831 xmlElementContentPtr ret;
832
833 if (cur == NULL) return(NULL);
834 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
835 if (ret == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000836 xmlErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000837 return(NULL);
838 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000839 if (cur->prefix != NULL)
840 ret->prefix = xmlStrdup(cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000841 ret->ocur = cur->ocur;
842 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000843 if (ret->c1 != NULL)
844 ret->c1->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000845 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000846 if (ret->c2 != NULL)
847 ret->c2->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000848 return(ret);
849}
850
851/**
852 * xmlFreeElementContent:
853 * @cur: the element content tree to free
854 *
855 * Free an element content structure. This is a recursive call !
856 */
857void
858xmlFreeElementContent(xmlElementContentPtr cur) {
859 if (cur == NULL) return;
860 switch (cur->type) {
861 case XML_ELEMENT_CONTENT_PCDATA:
862 case XML_ELEMENT_CONTENT_ELEMENT:
863 case XML_ELEMENT_CONTENT_SEQ:
864 case XML_ELEMENT_CONTENT_OR:
865 break;
866 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000867 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
868 "Internal: ELEMENT content corrupted invalid type\n",
869 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000870 return;
871 }
872 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
873 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
874 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000875 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000876 xmlFree(cur);
877}
878
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000879#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000880/**
881 * xmlDumpElementContent:
882 * @buf: An XML buffer
883 * @content: An element table
884 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
885 *
886 * This will dump the content of the element table as an XML DTD definition
887 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000888static void
Owen Taylor3473f882001-02-23 17:55:21 +0000889xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
890 if (content == NULL) return;
891
892 if (glob) xmlBufferWriteChar(buf, "(");
893 switch (content->type) {
894 case XML_ELEMENT_CONTENT_PCDATA:
895 xmlBufferWriteChar(buf, "#PCDATA");
896 break;
897 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000898 if (content->prefix != NULL) {
899 xmlBufferWriteCHAR(buf, content->prefix);
900 xmlBufferWriteChar(buf, ":");
901 }
Owen Taylor3473f882001-02-23 17:55:21 +0000902 xmlBufferWriteCHAR(buf, content->name);
903 break;
904 case XML_ELEMENT_CONTENT_SEQ:
905 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
906 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
907 xmlDumpElementContent(buf, content->c1, 1);
908 else
909 xmlDumpElementContent(buf, content->c1, 0);
910 xmlBufferWriteChar(buf, " , ");
911 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
912 xmlDumpElementContent(buf, content->c2, 1);
913 else
914 xmlDumpElementContent(buf, content->c2, 0);
915 break;
916 case XML_ELEMENT_CONTENT_OR:
917 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
918 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
919 xmlDumpElementContent(buf, content->c1, 1);
920 else
921 xmlDumpElementContent(buf, content->c1, 0);
922 xmlBufferWriteChar(buf, " | ");
923 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
924 xmlDumpElementContent(buf, content->c2, 1);
925 else
926 xmlDumpElementContent(buf, content->c2, 0);
927 break;
928 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000929 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
930 "Internal: ELEMENT content corrupted invalid type\n",
931 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000932 }
933 if (glob)
934 xmlBufferWriteChar(buf, ")");
935 switch (content->ocur) {
936 case XML_ELEMENT_CONTENT_ONCE:
937 break;
938 case XML_ELEMENT_CONTENT_OPT:
939 xmlBufferWriteChar(buf, "?");
940 break;
941 case XML_ELEMENT_CONTENT_MULT:
942 xmlBufferWriteChar(buf, "*");
943 break;
944 case XML_ELEMENT_CONTENT_PLUS:
945 xmlBufferWriteChar(buf, "+");
946 break;
947 }
948}
949
950/**
951 * xmlSprintfElementContent:
952 * @buf: an output buffer
953 * @content: An element table
954 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
955 *
Daniel Veillardd3d06722001-08-15 12:06:36 +0000956 * Deprecated, unsafe, use xmlSnprintfElementContent
957 */
958void
959xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
960 xmlElementContentPtr content ATTRIBUTE_UNUSED,
961 int glob ATTRIBUTE_UNUSED) {
962}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000963#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +0000964
965/**
966 * xmlSnprintfElementContent:
967 * @buf: an output buffer
968 * @size: the buffer size
969 * @content: An element table
970 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
971 *
Owen Taylor3473f882001-02-23 17:55:21 +0000972 * This will dump the content of the element content definition
973 * Intended just for the debug routine
974 */
975void
Daniel Veillardd3d06722001-08-15 12:06:36 +0000976xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int glob) {
977 int len;
978
Owen Taylor3473f882001-02-23 17:55:21 +0000979 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +0000980 len = strlen(buf);
981 if (size - len < 50) {
982 if ((size - len > 4) && (buf[len - 1] != '.'))
983 strcat(buf, " ...");
984 return;
985 }
Owen Taylor3473f882001-02-23 17:55:21 +0000986 if (glob) strcat(buf, "(");
987 switch (content->type) {
988 case XML_ELEMENT_CONTENT_PCDATA:
989 strcat(buf, "#PCDATA");
990 break;
991 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000992 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +0000993 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000994 strcat(buf, " ...");
995 return;
996 }
997 strcat(buf, (char *) content->prefix);
998 strcat(buf, ":");
999 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001000 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001001 strcat(buf, " ...");
1002 return;
1003 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001004 if (content->name != NULL)
1005 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001006 break;
1007 case XML_ELEMENT_CONTENT_SEQ:
1008 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1009 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001010 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001011 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001012 xmlSnprintfElementContent(buf, size, content->c1, 0);
1013 len = strlen(buf);
1014 if (size - len < 50) {
1015 if ((size - len > 4) && (buf[len - 1] != '.'))
1016 strcat(buf, " ...");
1017 return;
1018 }
Owen Taylor3473f882001-02-23 17:55:21 +00001019 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001020 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1021 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1022 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001023 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001024 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001025 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001026 break;
1027 case XML_ELEMENT_CONTENT_OR:
1028 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1029 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001030 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001031 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001032 xmlSnprintfElementContent(buf, size, content->c1, 0);
1033 len = strlen(buf);
1034 if (size - len < 50) {
1035 if ((size - len > 4) && (buf[len - 1] != '.'))
1036 strcat(buf, " ...");
1037 return;
1038 }
Owen Taylor3473f882001-02-23 17:55:21 +00001039 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001040 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1041 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1042 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001043 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001044 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001045 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001046 break;
1047 }
1048 if (glob)
1049 strcat(buf, ")");
1050 switch (content->ocur) {
1051 case XML_ELEMENT_CONTENT_ONCE:
1052 break;
1053 case XML_ELEMENT_CONTENT_OPT:
1054 strcat(buf, "?");
1055 break;
1056 case XML_ELEMENT_CONTENT_MULT:
1057 strcat(buf, "*");
1058 break;
1059 case XML_ELEMENT_CONTENT_PLUS:
1060 strcat(buf, "+");
1061 break;
1062 }
1063}
1064
1065/****************************************************************
1066 * *
1067 * Registration of DTD declarations *
1068 * *
1069 ****************************************************************/
1070
1071/**
1072 * xmlCreateElementTable:
1073 *
1074 * create and initialize an empty element hash table.
1075 *
1076 * Returns the xmlElementTablePtr just created or NULL in case of error.
1077 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001078static xmlElementTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001079xmlCreateElementTable(void) {
1080 return(xmlHashCreate(0));
1081}
1082
1083/**
1084 * xmlFreeElement:
1085 * @elem: An element
1086 *
1087 * Deallocate the memory used by an element definition
1088 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001089static void
Owen Taylor3473f882001-02-23 17:55:21 +00001090xmlFreeElement(xmlElementPtr elem) {
1091 if (elem == NULL) return;
1092 xmlUnlinkNode((xmlNodePtr) elem);
1093 xmlFreeElementContent(elem->content);
1094 if (elem->name != NULL)
1095 xmlFree((xmlChar *) elem->name);
1096 if (elem->prefix != NULL)
1097 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001098#ifdef LIBXML_REGEXP_ENABLED
1099 if (elem->contModel != NULL)
1100 xmlRegFreeRegexp(elem->contModel);
1101#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001102 xmlFree(elem);
1103}
1104
1105
1106/**
1107 * xmlAddElementDecl:
1108 * @ctxt: the validation context
1109 * @dtd: pointer to the DTD
1110 * @name: the entity name
1111 * @type: the element type
1112 * @content: the element content tree or NULL
1113 *
1114 * Register a new element declaration
1115 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001116 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001117 */
1118xmlElementPtr
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001119xmlAddElementDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1120 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001121 xmlElementTypeVal type,
1122 xmlElementContentPtr content) {
1123 xmlElementPtr ret;
1124 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001125 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001126 xmlChar *ns, *uqname;
1127
1128 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001129 return(NULL);
1130 }
1131 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001132 return(NULL);
1133 }
1134 switch (type) {
1135 case XML_ELEMENT_TYPE_EMPTY:
1136 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001137 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1138 "xmlAddElementDecl: content != NULL for EMPTY\n",
1139 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001140 return(NULL);
1141 }
1142 break;
1143 case XML_ELEMENT_TYPE_ANY:
1144 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001145 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1146 "xmlAddElementDecl: content != NULL for ANY\n",
1147 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001148 return(NULL);
1149 }
1150 break;
1151 case XML_ELEMENT_TYPE_MIXED:
1152 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001153 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1154 "xmlAddElementDecl: content == NULL for MIXED\n",
1155 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001156 return(NULL);
1157 }
1158 break;
1159 case XML_ELEMENT_TYPE_ELEMENT:
1160 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001161 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1162 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1163 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001164 return(NULL);
1165 }
1166 break;
1167 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001168 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1169 "Internal: ELEMENT decl corrupted invalid type\n",
1170 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001171 return(NULL);
1172 }
1173
1174 /*
1175 * check if name is a QName
1176 */
1177 uqname = xmlSplitQName2(name, &ns);
1178 if (uqname != NULL)
1179 name = uqname;
1180
1181 /*
1182 * Create the Element table if needed.
1183 */
1184 table = (xmlElementTablePtr) dtd->elements;
1185 if (table == NULL) {
1186 table = xmlCreateElementTable();
1187 dtd->elements = (void *) table;
1188 }
1189 if (table == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001190 xmlErrMemory(ctxt,
1191 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001192 if (uqname != NULL)
1193 xmlFree(uqname);
1194 if (ns != NULL)
1195 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001196 return(NULL);
1197 }
1198
Daniel Veillarda10efa82001-04-18 13:09:01 +00001199 /*
1200 * lookup old attributes inserted on an undefined element in the
1201 * internal subset.
1202 */
1203 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1204 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1205 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1206 oldAttributes = ret->attributes;
1207 ret->attributes = NULL;
1208 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1209 xmlFreeElement(ret);
1210 }
Owen Taylor3473f882001-02-23 17:55:21 +00001211 }
Owen Taylor3473f882001-02-23 17:55:21 +00001212
1213 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001214 * The element may already be present if one of its attribute
1215 * was registered first
1216 */
1217 ret = xmlHashLookup2(table, name, ns);
1218 if (ret != NULL) {
1219 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001220#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001221 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001222 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001223 */
1224 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard4432df22003-09-28 18:58:27 +00001225#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001226 if (uqname != NULL)
1227 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001228 if (ns != NULL)
1229 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001230 return(NULL);
1231 }
1232 } else {
1233 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1234 if (ret == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001235 xmlErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001236 if (uqname != NULL)
1237 xmlFree(uqname);
1238 if (ns != NULL)
1239 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001240 return(NULL);
1241 }
1242 memset(ret, 0, sizeof(xmlElement));
1243 ret->type = XML_ELEMENT_DECL;
1244
1245 /*
1246 * fill the structure.
1247 */
1248 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001249 if (ret->name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001250 xmlErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001251 if (uqname != NULL)
1252 xmlFree(uqname);
1253 if (ns != NULL)
1254 xmlFree(ns);
1255 xmlFree(ret);
1256 return(NULL);
1257 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001258 ret->prefix = ns;
1259
1260 /*
1261 * Validity Check:
1262 * Insertion must not fail
1263 */
1264 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001265#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001266 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001267 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001268 */
1269 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard4432df22003-09-28 18:58:27 +00001270#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001271 xmlFreeElement(ret);
1272 if (uqname != NULL)
1273 xmlFree(uqname);
1274 return(NULL);
1275 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001276 /*
1277 * For new element, may have attributes from earlier
1278 * definition in internal subset
1279 */
1280 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001281 }
1282
1283 /*
1284 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001285 */
1286 ret->etype = type;
Owen Taylor3473f882001-02-23 17:55:21 +00001287 ret->content = xmlCopyElementContent(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001288
1289 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001290 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001291 */
1292 ret->parent = dtd;
1293 ret->doc = dtd->doc;
1294 if (dtd->last == NULL) {
1295 dtd->children = dtd->last = (xmlNodePtr) ret;
1296 } else {
1297 dtd->last->next = (xmlNodePtr) ret;
1298 ret->prev = dtd->last;
1299 dtd->last = (xmlNodePtr) ret;
1300 }
1301 if (uqname != NULL)
1302 xmlFree(uqname);
1303 return(ret);
1304}
1305
1306/**
1307 * xmlFreeElementTable:
1308 * @table: An element table
1309 *
1310 * Deallocate the memory used by an element hash table.
1311 */
1312void
1313xmlFreeElementTable(xmlElementTablePtr table) {
1314 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1315}
1316
Daniel Veillard652327a2003-09-29 18:02:38 +00001317#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001318/**
1319 * xmlCopyElement:
1320 * @elem: An element
1321 *
1322 * Build a copy of an element.
1323 *
1324 * Returns the new xmlElementPtr or NULL in case of error.
1325 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001326static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001327xmlCopyElement(xmlElementPtr elem) {
1328 xmlElementPtr cur;
1329
1330 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1331 if (cur == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001332 xmlErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001333 return(NULL);
1334 }
1335 memset(cur, 0, sizeof(xmlElement));
1336 cur->type = XML_ELEMENT_DECL;
1337 cur->etype = elem->etype;
1338 if (elem->name != NULL)
1339 cur->name = xmlStrdup(elem->name);
1340 else
1341 cur->name = NULL;
1342 if (elem->prefix != NULL)
1343 cur->prefix = xmlStrdup(elem->prefix);
1344 else
1345 cur->prefix = NULL;
1346 cur->content = xmlCopyElementContent(elem->content);
1347 /* TODO : rebuild the attribute list on the copy */
1348 cur->attributes = NULL;
1349 return(cur);
1350}
1351
1352/**
1353 * xmlCopyElementTable:
1354 * @table: An element table
1355 *
1356 * Build a copy of an element table.
1357 *
1358 * Returns the new xmlElementTablePtr or NULL in case of error.
1359 */
1360xmlElementTablePtr
1361xmlCopyElementTable(xmlElementTablePtr table) {
1362 return((xmlElementTablePtr) xmlHashCopy(table,
1363 (xmlHashCopier) xmlCopyElement));
1364}
Daniel Veillard652327a2003-09-29 18:02:38 +00001365#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001366
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001367#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001368/**
1369 * xmlDumpElementDecl:
1370 * @buf: the XML buffer output
1371 * @elem: An element table
1372 *
1373 * This will dump the content of the element declaration as an XML
1374 * DTD definition
1375 */
1376void
1377xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1378 switch (elem->etype) {
1379 case XML_ELEMENT_TYPE_EMPTY:
1380 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001381 if (elem->prefix != NULL) {
1382 xmlBufferWriteCHAR(buf, elem->prefix);
1383 xmlBufferWriteChar(buf, ":");
1384 }
Owen Taylor3473f882001-02-23 17:55:21 +00001385 xmlBufferWriteCHAR(buf, elem->name);
1386 xmlBufferWriteChar(buf, " EMPTY>\n");
1387 break;
1388 case XML_ELEMENT_TYPE_ANY:
1389 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001390 if (elem->prefix != NULL) {
1391 xmlBufferWriteCHAR(buf, elem->prefix);
1392 xmlBufferWriteChar(buf, ":");
1393 }
Owen Taylor3473f882001-02-23 17:55:21 +00001394 xmlBufferWriteCHAR(buf, elem->name);
1395 xmlBufferWriteChar(buf, " ANY>\n");
1396 break;
1397 case XML_ELEMENT_TYPE_MIXED:
1398 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001399 if (elem->prefix != NULL) {
1400 xmlBufferWriteCHAR(buf, elem->prefix);
1401 xmlBufferWriteChar(buf, ":");
1402 }
Owen Taylor3473f882001-02-23 17:55:21 +00001403 xmlBufferWriteCHAR(buf, elem->name);
1404 xmlBufferWriteChar(buf, " ");
1405 xmlDumpElementContent(buf, elem->content, 1);
1406 xmlBufferWriteChar(buf, ">\n");
1407 break;
1408 case XML_ELEMENT_TYPE_ELEMENT:
1409 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001410 if (elem->prefix != NULL) {
1411 xmlBufferWriteCHAR(buf, elem->prefix);
1412 xmlBufferWriteChar(buf, ":");
1413 }
Owen Taylor3473f882001-02-23 17:55:21 +00001414 xmlBufferWriteCHAR(buf, elem->name);
1415 xmlBufferWriteChar(buf, " ");
1416 xmlDumpElementContent(buf, elem->content, 1);
1417 xmlBufferWriteChar(buf, ">\n");
1418 break;
1419 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001420 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1421 "Internal: ELEMENT struct corrupted invalid type\n",
1422 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001423 }
1424}
1425
1426/**
1427 * xmlDumpElementTable:
1428 * @buf: the XML buffer output
1429 * @table: An element table
1430 *
1431 * This will dump the content of the element table as an XML DTD definition
1432 */
1433void
1434xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1435 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDecl, buf);
1436}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001437#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001438
1439/**
1440 * xmlCreateEnumeration:
1441 * @name: the enumeration name or NULL
1442 *
1443 * create and initialize an enumeration attribute node.
1444 *
1445 * Returns the xmlEnumerationPtr just created or NULL in case
1446 * of error.
1447 */
1448xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001449xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001450 xmlEnumerationPtr ret;
1451
1452 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1453 if (ret == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001454 xmlErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001455 return(NULL);
1456 }
1457 memset(ret, 0, sizeof(xmlEnumeration));
1458
1459 if (name != NULL)
1460 ret->name = xmlStrdup(name);
1461 return(ret);
1462}
1463
1464/**
1465 * xmlFreeEnumeration:
1466 * @cur: the tree to free.
1467 *
1468 * free an enumeration attribute node (recursive).
1469 */
1470void
1471xmlFreeEnumeration(xmlEnumerationPtr cur) {
1472 if (cur == NULL) return;
1473
1474 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1475
1476 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001477 xmlFree(cur);
1478}
1479
Daniel Veillard652327a2003-09-29 18:02:38 +00001480#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001481/**
1482 * xmlCopyEnumeration:
1483 * @cur: the tree to copy.
1484 *
1485 * Copy an enumeration attribute node (recursive).
1486 *
1487 * Returns the xmlEnumerationPtr just created or NULL in case
1488 * of error.
1489 */
1490xmlEnumerationPtr
1491xmlCopyEnumeration(xmlEnumerationPtr cur) {
1492 xmlEnumerationPtr ret;
1493
1494 if (cur == NULL) return(NULL);
1495 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1496
1497 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1498 else ret->next = NULL;
1499
1500 return(ret);
1501}
Daniel Veillard652327a2003-09-29 18:02:38 +00001502#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001503
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001504#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001505/**
1506 * xmlDumpEnumeration:
1507 * @buf: the XML buffer output
1508 * @enum: An enumeration
1509 *
1510 * This will dump the content of the enumeration
1511 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001512static void
Owen Taylor3473f882001-02-23 17:55:21 +00001513xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1514 if (cur == NULL) return;
1515
1516 xmlBufferWriteCHAR(buf, cur->name);
1517 if (cur->next == NULL)
1518 xmlBufferWriteChar(buf, ")");
1519 else {
1520 xmlBufferWriteChar(buf, " | ");
1521 xmlDumpEnumeration(buf, cur->next);
1522 }
1523}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001524#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001525
1526/**
1527 * xmlCreateAttributeTable:
1528 *
1529 * create and initialize an empty attribute hash table.
1530 *
1531 * Returns the xmlAttributeTablePtr just created or NULL in case
1532 * of error.
1533 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001534static xmlAttributeTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001535xmlCreateAttributeTable(void) {
1536 return(xmlHashCreate(0));
1537}
1538
Daniel Veillard4432df22003-09-28 18:58:27 +00001539#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001540/**
1541 * xmlScanAttributeDeclCallback:
1542 * @attr: the attribute decl
1543 * @list: the list to update
1544 *
1545 * Callback called by xmlScanAttributeDecl when a new attribute
1546 * has to be entered in the list.
1547 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001548static void
Owen Taylor3473f882001-02-23 17:55:21 +00001549xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001550 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001551 attr->nexth = *list;
1552 *list = attr;
1553}
1554
1555/**
1556 * xmlScanAttributeDecl:
1557 * @dtd: pointer to the DTD
1558 * @elem: the element name
1559 *
1560 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001561 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001562 *
1563 * Returns the pointer to the first attribute decl in the chain,
1564 * possibly NULL.
1565 */
1566xmlAttributePtr
1567xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1568 xmlAttributePtr ret = NULL;
1569 xmlAttributeTablePtr table;
1570
1571 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001572 return(NULL);
1573 }
1574 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001575 return(NULL);
1576 }
1577 table = (xmlAttributeTablePtr) dtd->attributes;
1578 if (table == NULL)
1579 return(NULL);
1580
1581 /* WRONG !!! */
1582 xmlHashScan3(table, NULL, NULL, elem,
1583 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1584 return(ret);
1585}
1586
1587/**
1588 * xmlScanIDAttributeDecl:
1589 * @ctxt: the validation context
1590 * @elem: the element name
1591 *
1592 * Verify that the element don't have too many ID attributes
1593 * declared.
1594 *
1595 * Returns the number of ID attributes found.
1596 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001597static int
Owen Taylor3473f882001-02-23 17:55:21 +00001598xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1599 xmlAttributePtr cur;
1600 int ret = 0;
1601
1602 if (elem == NULL) return(0);
1603 cur = elem->attributes;
1604 while (cur != NULL) {
1605 if (cur->atype == XML_ATTRIBUTE_ID) {
1606 ret ++;
1607 if (ret > 1)
1608 VERROR(ctxt->userData,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001609 "Element %s has too many ID attributes defined : %s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00001610 elem->name, cur->name);
1611 }
1612 cur = cur->nexth;
1613 }
1614 return(ret);
1615}
Daniel Veillard4432df22003-09-28 18:58:27 +00001616#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001617
1618/**
1619 * xmlFreeAttribute:
1620 * @elem: An attribute
1621 *
1622 * Deallocate the memory used by an attribute definition
1623 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001624static void
Owen Taylor3473f882001-02-23 17:55:21 +00001625xmlFreeAttribute(xmlAttributePtr attr) {
1626 if (attr == NULL) return;
1627 xmlUnlinkNode((xmlNodePtr) attr);
1628 if (attr->tree != NULL)
1629 xmlFreeEnumeration(attr->tree);
1630 if (attr->elem != NULL)
1631 xmlFree((xmlChar *) attr->elem);
1632 if (attr->name != NULL)
1633 xmlFree((xmlChar *) attr->name);
1634 if (attr->defaultValue != NULL)
1635 xmlFree((xmlChar *) attr->defaultValue);
1636 if (attr->prefix != NULL)
1637 xmlFree((xmlChar *) attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001638 xmlFree(attr);
1639}
1640
1641
1642/**
1643 * xmlAddAttributeDecl:
1644 * @ctxt: the validation context
1645 * @dtd: pointer to the DTD
1646 * @elem: the element name
1647 * @name: the attribute name
1648 * @ns: the attribute namespace prefix
1649 * @type: the attribute type
1650 * @def: the attribute default type
1651 * @defaultValue: the attribute default value
1652 * @tree: if it's an enumeration, the associated list
1653 *
1654 * Register a new attribute declaration
1655 * Note that @tree becomes the ownership of the DTD
1656 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001657 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001658 */
1659xmlAttributePtr
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001660xmlAddAttributeDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1661 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001662 const xmlChar *name, const xmlChar *ns,
1663 xmlAttributeType type, xmlAttributeDefault def,
1664 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1665 xmlAttributePtr ret;
1666 xmlAttributeTablePtr table;
1667 xmlElementPtr elemDef;
1668
1669 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001670 xmlFreeEnumeration(tree);
1671 return(NULL);
1672 }
1673 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001674 xmlFreeEnumeration(tree);
1675 return(NULL);
1676 }
1677 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001678 xmlFreeEnumeration(tree);
1679 return(NULL);
1680 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001681
Daniel Veillard4432df22003-09-28 18:58:27 +00001682#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001683 /*
1684 * Check the type and possibly the default value.
1685 */
1686 switch (type) {
1687 case XML_ATTRIBUTE_CDATA:
1688 break;
1689 case XML_ATTRIBUTE_ID:
1690 break;
1691 case XML_ATTRIBUTE_IDREF:
1692 break;
1693 case XML_ATTRIBUTE_IDREFS:
1694 break;
1695 case XML_ATTRIBUTE_ENTITY:
1696 break;
1697 case XML_ATTRIBUTE_ENTITIES:
1698 break;
1699 case XML_ATTRIBUTE_NMTOKEN:
1700 break;
1701 case XML_ATTRIBUTE_NMTOKENS:
1702 break;
1703 case XML_ATTRIBUTE_ENUMERATION:
1704 break;
1705 case XML_ATTRIBUTE_NOTATION:
1706 break;
1707 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001708 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1709 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1710 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001711 xmlFreeEnumeration(tree);
1712 return(NULL);
1713 }
1714 if ((defaultValue != NULL) &&
1715 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillard58e44c92002-08-02 22:19:49 +00001716 VERROR(ctxt->userData, "Attribute %s of %s: invalid default value\n",
Owen Taylor3473f882001-02-23 17:55:21 +00001717 elem, name, defaultValue);
1718 defaultValue = NULL;
Daniel Veillardd01fd3e2002-02-18 22:27:47 +00001719 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001720 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001721#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001722
1723 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001724 * Check first that an attribute defined in the external subset wasn't
1725 * already defined in the internal subset
1726 */
1727 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1728 (dtd->doc->intSubset != NULL) &&
1729 (dtd->doc->intSubset->attributes != NULL)) {
1730 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1731 if (ret != NULL)
1732 return(NULL);
1733 }
1734
1735 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001736 * Create the Attribute table if needed.
1737 */
1738 table = (xmlAttributeTablePtr) dtd->attributes;
1739 if (table == NULL) {
1740 table = xmlCreateAttributeTable();
1741 dtd->attributes = (void *) table;
1742 }
1743 if (table == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001744 xmlErrMemory(ctxt,
1745 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001746 return(NULL);
1747 }
1748
1749
1750 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1751 if (ret == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001752 xmlErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001753 return(NULL);
1754 }
1755 memset(ret, 0, sizeof(xmlAttribute));
1756 ret->type = XML_ATTRIBUTE_DECL;
1757
1758 /*
1759 * fill the structure.
1760 */
1761 ret->atype = type;
1762 ret->name = xmlStrdup(name);
1763 ret->prefix = xmlStrdup(ns);
1764 ret->elem = xmlStrdup(elem);
1765 ret->def = def;
1766 ret->tree = tree;
1767 if (defaultValue != NULL)
1768 ret->defaultValue = xmlStrdup(defaultValue);
1769
1770 /*
1771 * Validity Check:
1772 * Search the DTD for previous declarations of the ATTLIST
1773 */
1774 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001775#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001776 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001777 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00001778 */
1779 VWARNING(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00001780 "Attribute %s of element %s: already defined\n",
Owen Taylor3473f882001-02-23 17:55:21 +00001781 name, elem);
Daniel Veillard4432df22003-09-28 18:58:27 +00001782#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001783 xmlFreeAttribute(ret);
1784 return(NULL);
1785 }
1786
1787 /*
1788 * Validity Check:
1789 * Multiple ID per element
1790 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001791 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001792 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00001793
Daniel Veillard4432df22003-09-28 18:58:27 +00001794#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001795 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00001796 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001797 VERROR(ctxt->userData,
1798 "Element %s has too may ID attributes defined : %s\n",
1799 elem, name);
Daniel Veillardc7612992002-02-17 22:47:37 +00001800 ctxt->valid = 0;
1801 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001802#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00001803
Daniel Veillard48da9102001-08-07 01:10:10 +00001804 /*
1805 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001806 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00001807 */
1808 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1809 ((ret->prefix != NULL &&
1810 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1811 ret->nexth = elemDef->attributes;
1812 elemDef->attributes = ret;
1813 } else {
1814 xmlAttributePtr tmp = elemDef->attributes;
1815
1816 while ((tmp != NULL) &&
1817 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1818 ((ret->prefix != NULL &&
1819 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1820 if (tmp->nexth == NULL)
1821 break;
1822 tmp = tmp->nexth;
1823 }
1824 if (tmp != NULL) {
1825 ret->nexth = tmp->nexth;
1826 tmp->nexth = ret;
1827 } else {
1828 ret->nexth = elemDef->attributes;
1829 elemDef->attributes = ret;
1830 }
1831 }
Owen Taylor3473f882001-02-23 17:55:21 +00001832 }
1833
1834 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001835 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001836 */
1837 ret->parent = dtd;
1838 ret->doc = dtd->doc;
1839 if (dtd->last == NULL) {
1840 dtd->children = dtd->last = (xmlNodePtr) ret;
1841 } else {
1842 dtd->last->next = (xmlNodePtr) ret;
1843 ret->prev = dtd->last;
1844 dtd->last = (xmlNodePtr) ret;
1845 }
1846 return(ret);
1847}
1848
1849/**
1850 * xmlFreeAttributeTable:
1851 * @table: An attribute table
1852 *
1853 * Deallocate the memory used by an entities hash table.
1854 */
1855void
1856xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1857 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
1858}
1859
Daniel Veillard652327a2003-09-29 18:02:38 +00001860#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001861/**
1862 * xmlCopyAttribute:
1863 * @attr: An attribute
1864 *
1865 * Build a copy of an attribute.
1866 *
1867 * Returns the new xmlAttributePtr or NULL in case of error.
1868 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001869static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001870xmlCopyAttribute(xmlAttributePtr attr) {
1871 xmlAttributePtr cur;
1872
1873 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1874 if (cur == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001875 xmlErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001876 return(NULL);
1877 }
1878 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00001879 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00001880 cur->atype = attr->atype;
1881 cur->def = attr->def;
1882 cur->tree = xmlCopyEnumeration(attr->tree);
1883 if (attr->elem != NULL)
1884 cur->elem = xmlStrdup(attr->elem);
1885 if (attr->name != NULL)
1886 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00001887 if (attr->prefix != NULL)
1888 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001889 if (attr->defaultValue != NULL)
1890 cur->defaultValue = xmlStrdup(attr->defaultValue);
1891 return(cur);
1892}
1893
1894/**
1895 * xmlCopyAttributeTable:
1896 * @table: An attribute table
1897 *
1898 * Build a copy of an attribute table.
1899 *
1900 * Returns the new xmlAttributeTablePtr or NULL in case of error.
1901 */
1902xmlAttributeTablePtr
1903xmlCopyAttributeTable(xmlAttributeTablePtr table) {
1904 return((xmlAttributeTablePtr) xmlHashCopy(table,
1905 (xmlHashCopier) xmlCopyAttribute));
1906}
Daniel Veillard652327a2003-09-29 18:02:38 +00001907#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001908
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001909#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001910/**
1911 * xmlDumpAttributeDecl:
1912 * @buf: the XML buffer output
1913 * @attr: An attribute declaration
1914 *
1915 * This will dump the content of the attribute declaration as an XML
1916 * DTD definition
1917 */
1918void
1919xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
1920 xmlBufferWriteChar(buf, "<!ATTLIST ");
1921 xmlBufferWriteCHAR(buf, attr->elem);
1922 xmlBufferWriteChar(buf, " ");
1923 if (attr->prefix != NULL) {
1924 xmlBufferWriteCHAR(buf, attr->prefix);
1925 xmlBufferWriteChar(buf, ":");
1926 }
1927 xmlBufferWriteCHAR(buf, attr->name);
1928 switch (attr->atype) {
1929 case XML_ATTRIBUTE_CDATA:
1930 xmlBufferWriteChar(buf, " CDATA");
1931 break;
1932 case XML_ATTRIBUTE_ID:
1933 xmlBufferWriteChar(buf, " ID");
1934 break;
1935 case XML_ATTRIBUTE_IDREF:
1936 xmlBufferWriteChar(buf, " IDREF");
1937 break;
1938 case XML_ATTRIBUTE_IDREFS:
1939 xmlBufferWriteChar(buf, " IDREFS");
1940 break;
1941 case XML_ATTRIBUTE_ENTITY:
1942 xmlBufferWriteChar(buf, " ENTITY");
1943 break;
1944 case XML_ATTRIBUTE_ENTITIES:
1945 xmlBufferWriteChar(buf, " ENTITIES");
1946 break;
1947 case XML_ATTRIBUTE_NMTOKEN:
1948 xmlBufferWriteChar(buf, " NMTOKEN");
1949 break;
1950 case XML_ATTRIBUTE_NMTOKENS:
1951 xmlBufferWriteChar(buf, " NMTOKENS");
1952 break;
1953 case XML_ATTRIBUTE_ENUMERATION:
1954 xmlBufferWriteChar(buf, " (");
1955 xmlDumpEnumeration(buf, attr->tree);
1956 break;
1957 case XML_ATTRIBUTE_NOTATION:
1958 xmlBufferWriteChar(buf, " NOTATION (");
1959 xmlDumpEnumeration(buf, attr->tree);
1960 break;
1961 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001962 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1963 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1964 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001965 }
1966 switch (attr->def) {
1967 case XML_ATTRIBUTE_NONE:
1968 break;
1969 case XML_ATTRIBUTE_REQUIRED:
1970 xmlBufferWriteChar(buf, " #REQUIRED");
1971 break;
1972 case XML_ATTRIBUTE_IMPLIED:
1973 xmlBufferWriteChar(buf, " #IMPLIED");
1974 break;
1975 case XML_ATTRIBUTE_FIXED:
1976 xmlBufferWriteChar(buf, " #FIXED");
1977 break;
1978 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001979 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1980 "Internal: ATTRIBUTE struct corrupted invalid def\n",
1981 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001982 }
1983 if (attr->defaultValue != NULL) {
1984 xmlBufferWriteChar(buf, " ");
1985 xmlBufferWriteQuotedString(buf, attr->defaultValue);
1986 }
1987 xmlBufferWriteChar(buf, ">\n");
1988}
1989
1990/**
1991 * xmlDumpAttributeTable:
1992 * @buf: the XML buffer output
1993 * @table: An attribute table
1994 *
1995 * This will dump the content of the attribute table as an XML DTD definition
1996 */
1997void
1998xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
1999 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDecl, buf);
2000}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002001#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002002
2003/************************************************************************
2004 * *
2005 * NOTATIONs *
2006 * *
2007 ************************************************************************/
2008/**
2009 * xmlCreateNotationTable:
2010 *
2011 * create and initialize an empty notation hash table.
2012 *
2013 * Returns the xmlNotationTablePtr just created or NULL in case
2014 * of error.
2015 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002016static xmlNotationTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002017xmlCreateNotationTable(void) {
2018 return(xmlHashCreate(0));
2019}
2020
2021/**
2022 * xmlFreeNotation:
2023 * @not: A notation
2024 *
2025 * Deallocate the memory used by an notation definition
2026 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002027static void
Owen Taylor3473f882001-02-23 17:55:21 +00002028xmlFreeNotation(xmlNotationPtr nota) {
2029 if (nota == NULL) return;
2030 if (nota->name != NULL)
2031 xmlFree((xmlChar *) nota->name);
2032 if (nota->PublicID != NULL)
2033 xmlFree((xmlChar *) nota->PublicID);
2034 if (nota->SystemID != NULL)
2035 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002036 xmlFree(nota);
2037}
2038
2039
2040/**
2041 * xmlAddNotationDecl:
2042 * @dtd: pointer to the DTD
2043 * @ctxt: the validation context
2044 * @name: the entity name
2045 * @PublicID: the public identifier or NULL
2046 * @SystemID: the system identifier or NULL
2047 *
2048 * Register a new notation declaration
2049 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002050 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002051 */
2052xmlNotationPtr
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00002053xmlAddNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002054 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002055 const xmlChar *PublicID, const xmlChar *SystemID) {
2056 xmlNotationPtr ret;
2057 xmlNotationTablePtr table;
2058
2059 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002060 return(NULL);
2061 }
2062 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002063 return(NULL);
2064 }
2065 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002066 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002067 }
2068
2069 /*
2070 * Create the Notation table if needed.
2071 */
2072 table = (xmlNotationTablePtr) dtd->notations;
2073 if (table == NULL)
2074 dtd->notations = table = xmlCreateNotationTable();
2075 if (table == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002076 xmlErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002077 "xmlAddNotationDecl: Table creation failed!\n");
2078 return(NULL);
2079 }
2080
2081 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2082 if (ret == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002083 xmlErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002084 return(NULL);
2085 }
2086 memset(ret, 0, sizeof(xmlNotation));
2087
2088 /*
2089 * fill the structure.
2090 */
2091 ret->name = xmlStrdup(name);
2092 if (SystemID != NULL)
2093 ret->SystemID = xmlStrdup(SystemID);
2094 if (PublicID != NULL)
2095 ret->PublicID = xmlStrdup(PublicID);
2096
2097 /*
2098 * Validity Check:
2099 * Check the DTD for previous declarations of the ATTLIST
2100 */
2101 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002102#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002103 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2104 "xmlAddNotationDecl: %s already defined\n",
2105 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002106#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002107 xmlFreeNotation(ret);
2108 return(NULL);
2109 }
2110 return(ret);
2111}
2112
2113/**
2114 * xmlFreeNotationTable:
2115 * @table: An notation table
2116 *
2117 * Deallocate the memory used by an entities hash table.
2118 */
2119void
2120xmlFreeNotationTable(xmlNotationTablePtr table) {
2121 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2122}
2123
Daniel Veillard652327a2003-09-29 18:02:38 +00002124#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002125/**
2126 * xmlCopyNotation:
2127 * @nota: A notation
2128 *
2129 * Build a copy of a notation.
2130 *
2131 * Returns the new xmlNotationPtr or NULL in case of error.
2132 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002133static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002134xmlCopyNotation(xmlNotationPtr nota) {
2135 xmlNotationPtr cur;
2136
2137 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2138 if (cur == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002139 xmlErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002140 return(NULL);
2141 }
2142 if (nota->name != NULL)
2143 cur->name = xmlStrdup(nota->name);
2144 else
2145 cur->name = NULL;
2146 if (nota->PublicID != NULL)
2147 cur->PublicID = xmlStrdup(nota->PublicID);
2148 else
2149 cur->PublicID = NULL;
2150 if (nota->SystemID != NULL)
2151 cur->SystemID = xmlStrdup(nota->SystemID);
2152 else
2153 cur->SystemID = NULL;
2154 return(cur);
2155}
2156
2157/**
2158 * xmlCopyNotationTable:
2159 * @table: A notation table
2160 *
2161 * Build a copy of a notation table.
2162 *
2163 * Returns the new xmlNotationTablePtr or NULL in case of error.
2164 */
2165xmlNotationTablePtr
2166xmlCopyNotationTable(xmlNotationTablePtr table) {
2167 return((xmlNotationTablePtr) xmlHashCopy(table,
2168 (xmlHashCopier) xmlCopyNotation));
2169}
Daniel Veillard652327a2003-09-29 18:02:38 +00002170#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002171
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002172#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002173/**
2174 * xmlDumpNotationDecl:
2175 * @buf: the XML buffer output
2176 * @nota: A notation declaration
2177 *
2178 * This will dump the content the notation declaration as an XML DTD definition
2179 */
2180void
2181xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2182 xmlBufferWriteChar(buf, "<!NOTATION ");
2183 xmlBufferWriteCHAR(buf, nota->name);
2184 if (nota->PublicID != NULL) {
2185 xmlBufferWriteChar(buf, " PUBLIC ");
2186 xmlBufferWriteQuotedString(buf, nota->PublicID);
2187 if (nota->SystemID != NULL) {
2188 xmlBufferWriteChar(buf, " ");
2189 xmlBufferWriteCHAR(buf, nota->SystemID);
2190 }
2191 } else {
2192 xmlBufferWriteChar(buf, " SYSTEM ");
2193 xmlBufferWriteCHAR(buf, nota->SystemID);
2194 }
2195 xmlBufferWriteChar(buf, " >\n");
2196}
2197
2198/**
2199 * xmlDumpNotationTable:
2200 * @buf: the XML buffer output
2201 * @table: A notation table
2202 *
2203 * This will dump the content of the notation table as an XML DTD definition
2204 */
2205void
2206xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2207 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDecl, buf);
2208}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002209#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002210
2211/************************************************************************
2212 * *
2213 * IDs *
2214 * *
2215 ************************************************************************/
2216/**
2217 * xmlCreateIDTable:
2218 *
2219 * create and initialize an empty id hash table.
2220 *
2221 * Returns the xmlIDTablePtr just created or NULL in case
2222 * of error.
2223 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002224static xmlIDTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002225xmlCreateIDTable(void) {
2226 return(xmlHashCreate(0));
2227}
2228
2229/**
2230 * xmlFreeID:
2231 * @not: A id
2232 *
2233 * Deallocate the memory used by an id definition
2234 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002235static void
Owen Taylor3473f882001-02-23 17:55:21 +00002236xmlFreeID(xmlIDPtr id) {
2237 if (id == NULL) return;
2238 if (id->value != NULL)
2239 xmlFree((xmlChar *) id->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002240 if (id->name != NULL)
2241 xmlFree((xmlChar *) id->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002242 xmlFree(id);
2243}
2244
2245/**
2246 * xmlAddID:
2247 * @ctxt: the validation context
2248 * @doc: pointer to the document
2249 * @value: the value name
2250 * @attr: the attribute holding the ID
2251 *
2252 * Register a new id declaration
2253 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002254 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002255 */
2256xmlIDPtr
2257xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2258 xmlAttrPtr attr) {
2259 xmlIDPtr ret;
2260 xmlIDTablePtr table;
2261
2262 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002263 return(NULL);
2264 }
2265 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002266 return(NULL);
2267 }
2268 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002269 return(NULL);
2270 }
2271
2272 /*
2273 * Create the ID table if needed.
2274 */
2275 table = (xmlIDTablePtr) doc->ids;
2276 if (table == NULL)
2277 doc->ids = table = xmlCreateIDTable();
2278 if (table == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002279 xmlErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002280 "xmlAddID: Table creation failed!\n");
2281 return(NULL);
2282 }
2283
2284 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2285 if (ret == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002286 xmlErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002287 return(NULL);
2288 }
2289
2290 /*
2291 * fill the structure.
2292 */
2293 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002294 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2295 /*
2296 * Operating in streaming mode, attr is gonna disapear
2297 */
2298 ret->name = xmlStrdup(attr->name);
2299 ret->attr = NULL;
2300 } else {
2301 ret->attr = attr;
2302 ret->name = NULL;
2303 }
2304 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002305
2306 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002307#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002308 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002309 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002310 */
Daniel Veillard76575762002-09-05 14:21:15 +00002311 if (ctxt != NULL) {
2312 VECTXT(ctxt, attr->parent);
Daniel Veillardc5f05ad2002-02-10 11:57:22 +00002313 VERROR(ctxt->userData, "ID %s already defined\n", value);
Daniel Veillard76575762002-09-05 14:21:15 +00002314 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002315#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002316 xmlFreeID(ret);
2317 return(NULL);
2318 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002319 if (attr != NULL)
2320 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002321 return(ret);
2322}
2323
2324/**
2325 * xmlFreeIDTable:
2326 * @table: An id table
2327 *
2328 * Deallocate the memory used by an ID hash table.
2329 */
2330void
2331xmlFreeIDTable(xmlIDTablePtr table) {
2332 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2333}
2334
2335/**
2336 * xmlIsID:
2337 * @doc: the document
2338 * @elem: the element carrying the attribute
2339 * @attr: the attribute
2340 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002341 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002342 * then this is done if DTD loading has been requested. In the case
2343 * of HTML documents parsed with the HTML parser, then ID detection is
2344 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002345 *
2346 * Returns 0 or 1 depending on the lookup result
2347 */
2348int
2349xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2350 if (doc == NULL) return(0);
2351 if (attr == NULL) return(0);
2352 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2353 return(0);
2354 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2355 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2356 (xmlStrEqual(BAD_CAST "name", attr->name)))
2357 return(1);
2358 return(0);
2359 } else {
2360 xmlAttributePtr attrDecl;
2361
2362 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002363 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002364 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002365 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002366
2367 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002368 if (fullname == NULL)
2369 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002370 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2371 attr->name);
2372 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2373 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2374 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002375 if ((fullname != fn) && (fullname != elem->name))
2376 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002377 } else {
2378 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2379 attr->name);
2380 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2381 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2382 attr->name);
2383 }
Owen Taylor3473f882001-02-23 17:55:21 +00002384
2385 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2386 return(1);
2387 }
2388 return(0);
2389}
2390
2391/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002392 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002393 * @doc: the document
2394 * @attr: the attribute
2395 *
2396 * Remove the given attribute from the ID table maintained internally.
2397 *
2398 * Returns -1 if the lookup failed and 0 otherwise
2399 */
2400int
2401xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2402 xmlAttrPtr cur;
2403 xmlIDTablePtr table;
2404 xmlChar *ID;
2405
2406 if (doc == NULL) return(-1);
2407 if (attr == NULL) return(-1);
2408 table = (xmlIDTablePtr) doc->ids;
2409 if (table == NULL)
2410 return(-1);
2411
2412 if (attr == NULL)
2413 return(-1);
2414 ID = xmlNodeListGetString(doc, attr->children, 1);
2415 if (ID == NULL)
2416 return(-1);
2417 cur = xmlHashLookup(table, ID);
2418 if (cur != attr) {
2419 xmlFree(ID);
2420 return(-1);
2421 }
2422 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
2423 xmlFree(ID);
2424 return(0);
2425}
2426
2427/**
2428 * xmlGetID:
2429 * @doc: pointer to the document
2430 * @ID: the ID value
2431 *
2432 * Search the attribute declaring the given ID
2433 *
2434 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2435 */
2436xmlAttrPtr
2437xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2438 xmlIDTablePtr table;
2439 xmlIDPtr id;
2440
2441 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002442 return(NULL);
2443 }
2444
2445 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002446 return(NULL);
2447 }
2448
2449 table = (xmlIDTablePtr) doc->ids;
2450 if (table == NULL)
2451 return(NULL);
2452
2453 id = xmlHashLookup(table, ID);
2454 if (id == NULL)
2455 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002456 if (id->attr == NULL) {
2457 /*
2458 * We are operating on a stream, return a well known reference
2459 * since the attribute node doesn't exist anymore
2460 */
2461 return((xmlAttrPtr) doc);
2462 }
Owen Taylor3473f882001-02-23 17:55:21 +00002463 return(id->attr);
2464}
2465
2466/************************************************************************
2467 * *
2468 * Refs *
2469 * *
2470 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002471typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002472{
2473 xmlListPtr l;
2474 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002475} xmlRemoveMemo;
2476
2477typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2478
2479typedef struct xmlValidateMemo_t
2480{
2481 xmlValidCtxtPtr ctxt;
2482 const xmlChar *name;
2483} xmlValidateMemo;
2484
2485typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002486
2487/**
2488 * xmlCreateRefTable:
2489 *
2490 * create and initialize an empty ref hash table.
2491 *
2492 * Returns the xmlRefTablePtr just created or NULL in case
2493 * of error.
2494 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002495static xmlRefTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002496xmlCreateRefTable(void) {
2497 return(xmlHashCreate(0));
2498}
2499
2500/**
2501 * xmlFreeRef:
2502 * @lk: A list link
2503 *
2504 * Deallocate the memory used by a ref definition
2505 */
2506static void
2507xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002508 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2509 if (ref == NULL) return;
2510 if (ref->value != NULL)
2511 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002512 if (ref->name != NULL)
2513 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002514 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002515}
2516
2517/**
2518 * xmlFreeRefList:
2519 * @list_ref: A list of references.
2520 *
2521 * Deallocate the memory used by a list of references
2522 */
2523static void
2524xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002525 if (list_ref == NULL) return;
2526 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002527}
2528
2529/**
2530 * xmlWalkRemoveRef:
2531 * @data: Contents of current link
2532 * @user: Value supplied by the user
2533 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002534 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002535 */
2536static int
2537xmlWalkRemoveRef(const void *data, const void *user)
2538{
Daniel Veillard37721922001-05-04 15:21:12 +00002539 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2540 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2541 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002542
Daniel Veillard37721922001-05-04 15:21:12 +00002543 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2544 xmlListRemoveFirst(ref_list, (void *)data);
2545 return 0;
2546 }
2547 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002548}
2549
2550/**
2551 * xmlAddRef:
2552 * @ctxt: the validation context
2553 * @doc: pointer to the document
2554 * @value: the value name
2555 * @attr: the attribute holding the Ref
2556 *
2557 * Register a new ref declaration
2558 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002559 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002560 */
2561xmlRefPtr
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00002562xmlAddRef(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002563 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002564 xmlRefPtr ret;
2565 xmlRefTablePtr table;
2566 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002567
Daniel Veillard37721922001-05-04 15:21:12 +00002568 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002569 return(NULL);
2570 }
2571 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002572 return(NULL);
2573 }
2574 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002575 return(NULL);
2576 }
Owen Taylor3473f882001-02-23 17:55:21 +00002577
Daniel Veillard37721922001-05-04 15:21:12 +00002578 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002579 * Create the Ref table if needed.
2580 */
Daniel Veillard37721922001-05-04 15:21:12 +00002581 table = (xmlRefTablePtr) doc->refs;
2582 if (table == NULL)
2583 doc->refs = table = xmlCreateRefTable();
2584 if (table == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002585 xmlErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002586 "xmlAddRef: Table creation failed!\n");
2587 return(NULL);
2588 }
Owen Taylor3473f882001-02-23 17:55:21 +00002589
Daniel Veillard37721922001-05-04 15:21:12 +00002590 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2591 if (ret == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002592 xmlErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002593 return(NULL);
2594 }
Owen Taylor3473f882001-02-23 17:55:21 +00002595
Daniel Veillard37721922001-05-04 15:21:12 +00002596 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002597 * fill the structure.
2598 */
Daniel Veillard37721922001-05-04 15:21:12 +00002599 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002600 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2601 /*
2602 * Operating in streaming mode, attr is gonna disapear
2603 */
2604 ret->name = xmlStrdup(attr->name);
2605 ret->attr = NULL;
2606 } else {
2607 ret->name = NULL;
2608 ret->attr = attr;
2609 }
2610 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002611
Daniel Veillard37721922001-05-04 15:21:12 +00002612 /* To add a reference :-
2613 * References are maintained as a list of references,
2614 * Lookup the entry, if no entry create new nodelist
2615 * Add the owning node to the NodeList
2616 * Return the ref
2617 */
Owen Taylor3473f882001-02-23 17:55:21 +00002618
Daniel Veillard37721922001-05-04 15:21:12 +00002619 if (NULL == (ref_list = xmlHashLookup(table, value))) {
2620 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, NULL))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002621 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2622 "xmlAddRef: Reference list creation failed!\n",
2623 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002624 return(NULL);
2625 }
2626 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2627 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002628 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2629 "xmlAddRef: Reference list insertion failed!\n",
2630 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002631 return(NULL);
2632 }
2633 }
2634 xmlListInsert(ref_list, ret);
2635 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002636}
2637
2638/**
2639 * xmlFreeRefTable:
2640 * @table: An ref table
2641 *
2642 * Deallocate the memory used by an Ref hash table.
2643 */
2644void
2645xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002646 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002647}
2648
2649/**
2650 * xmlIsRef:
2651 * @doc: the document
2652 * @elem: the element carrying the attribute
2653 * @attr: the attribute
2654 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002655 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00002656 * then this is simple, otherwise we use an heuristic: name Ref (upper
2657 * or lowercase).
2658 *
2659 * Returns 0 or 1 depending on the lookup result
2660 */
2661int
2662xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002663 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2664 return(0);
2665 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2666 /* TODO @@@ */
2667 return(0);
2668 } else {
2669 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00002670
Daniel Veillard37721922001-05-04 15:21:12 +00002671 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2672 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2673 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2674 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002675
Daniel Veillard37721922001-05-04 15:21:12 +00002676 if ((attrDecl != NULL) &&
2677 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2678 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2679 return(1);
2680 }
2681 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002682}
2683
2684/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002685 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00002686 * @doc: the document
2687 * @attr: the attribute
2688 *
2689 * Remove the given attribute from the Ref table maintained internally.
2690 *
2691 * Returns -1 if the lookup failed and 0 otherwise
2692 */
2693int
2694xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002695 xmlListPtr ref_list;
2696 xmlRefTablePtr table;
2697 xmlChar *ID;
2698 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00002699
Daniel Veillard37721922001-05-04 15:21:12 +00002700 if (doc == NULL) return(-1);
2701 if (attr == NULL) return(-1);
2702 table = (xmlRefTablePtr) doc->refs;
2703 if (table == NULL)
2704 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002705
Daniel Veillard37721922001-05-04 15:21:12 +00002706 if (attr == NULL)
2707 return(-1);
2708 ID = xmlNodeListGetString(doc, attr->children, 1);
2709 if (ID == NULL)
2710 return(-1);
2711 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00002712
Daniel Veillard37721922001-05-04 15:21:12 +00002713 if(ref_list == NULL) {
2714 xmlFree(ID);
2715 return (-1);
2716 }
2717 /* At this point, ref_list refers to a list of references which
2718 * have the same key as the supplied attr. Our list of references
2719 * is ordered by reference address and we don't have that information
2720 * here to use when removing. We'll have to walk the list and
2721 * check for a matching attribute, when we find one stop the walk
2722 * and remove the entry.
2723 * The list is ordered by reference, so that means we don't have the
2724 * key. Passing the list and the reference to the walker means we
2725 * will have enough data to be able to remove the entry.
2726 */
2727 target.l = ref_list;
2728 target.ap = attr;
2729
2730 /* Remove the supplied attr from our list */
2731 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00002732
Daniel Veillard37721922001-05-04 15:21:12 +00002733 /*If the list is empty then remove the list entry in the hash */
2734 if (xmlListEmpty(ref_list))
2735 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2736 xmlFreeRefList);
2737 xmlFree(ID);
2738 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002739}
2740
2741/**
2742 * xmlGetRefs:
2743 * @doc: pointer to the document
2744 * @ID: the ID value
2745 *
2746 * Find the set of references for the supplied ID.
2747 *
2748 * Returns NULL if not found, otherwise node set for the ID.
2749 */
2750xmlListPtr
2751xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00002752 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00002753
Daniel Veillard37721922001-05-04 15:21:12 +00002754 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002755 return(NULL);
2756 }
Owen Taylor3473f882001-02-23 17:55:21 +00002757
Daniel Veillard37721922001-05-04 15:21:12 +00002758 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002759 return(NULL);
2760 }
Owen Taylor3473f882001-02-23 17:55:21 +00002761
Daniel Veillard37721922001-05-04 15:21:12 +00002762 table = (xmlRefTablePtr) doc->refs;
2763 if (table == NULL)
2764 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002765
Daniel Veillard37721922001-05-04 15:21:12 +00002766 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00002767}
2768
2769/************************************************************************
2770 * *
2771 * Routines for validity checking *
2772 * *
2773 ************************************************************************/
2774
2775/**
2776 * xmlGetDtdElementDesc:
2777 * @dtd: a pointer to the DtD to search
2778 * @name: the element name
2779 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002780 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002781 *
2782 * returns the xmlElementPtr if found or NULL
2783 */
2784
2785xmlElementPtr
2786xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2787 xmlElementTablePtr table;
2788 xmlElementPtr cur;
2789 xmlChar *uqname = NULL, *prefix = NULL;
2790
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002791 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002792 if (dtd->elements == NULL)
2793 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002794 table = (xmlElementTablePtr) dtd->elements;
2795
2796 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002797 if (uqname != NULL)
2798 name = uqname;
2799 cur = xmlHashLookup2(table, name, prefix);
2800 if (prefix != NULL) xmlFree(prefix);
2801 if (uqname != NULL) xmlFree(uqname);
2802 return(cur);
2803}
2804/**
2805 * xmlGetDtdElementDesc2:
2806 * @dtd: a pointer to the DtD to search
2807 * @name: the element name
2808 * @create: create an empty description if not found
2809 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002810 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00002811 *
2812 * returns the xmlElementPtr if found or NULL
2813 */
2814
Daniel Veillard86fd5a72001-12-13 14:55:21 +00002815static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00002816xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
2817 xmlElementTablePtr table;
2818 xmlElementPtr cur;
2819 xmlChar *uqname = NULL, *prefix = NULL;
2820
2821 if (dtd == NULL) return(NULL);
2822 if (dtd->elements == NULL) {
2823 if (!create)
2824 return(NULL);
2825 /*
2826 * Create the Element table if needed.
2827 */
2828 table = (xmlElementTablePtr) dtd->elements;
2829 if (table == NULL) {
2830 table = xmlCreateElementTable();
2831 dtd->elements = (void *) table;
2832 }
2833 if (table == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002834 xmlErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00002835 return(NULL);
2836 }
2837 }
2838 table = (xmlElementTablePtr) dtd->elements;
2839
2840 uqname = xmlSplitQName2(name, &prefix);
2841 if (uqname != NULL)
2842 name = uqname;
2843 cur = xmlHashLookup2(table, name, prefix);
2844 if ((cur == NULL) && (create)) {
2845 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
2846 if (cur == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002847 xmlErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00002848 return(NULL);
2849 }
2850 memset(cur, 0, sizeof(xmlElement));
2851 cur->type = XML_ELEMENT_DECL;
2852
2853 /*
2854 * fill the structure.
2855 */
2856 cur->name = xmlStrdup(name);
2857 cur->prefix = xmlStrdup(prefix);
2858 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
2859
2860 xmlHashAddEntry2(table, name, prefix, cur);
2861 }
2862 if (prefix != NULL) xmlFree(prefix);
2863 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00002864 return(cur);
2865}
2866
2867/**
2868 * xmlGetDtdQElementDesc:
2869 * @dtd: a pointer to the DtD to search
2870 * @name: the element name
2871 * @prefix: the element namespace prefix
2872 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002873 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002874 *
2875 * returns the xmlElementPtr if found or NULL
2876 */
2877
Daniel Veillard48da9102001-08-07 01:10:10 +00002878xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002879xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
2880 const xmlChar *prefix) {
2881 xmlElementTablePtr table;
2882
2883 if (dtd == NULL) return(NULL);
2884 if (dtd->elements == NULL) return(NULL);
2885 table = (xmlElementTablePtr) dtd->elements;
2886
2887 return(xmlHashLookup2(table, name, prefix));
2888}
2889
2890/**
2891 * xmlGetDtdAttrDesc:
2892 * @dtd: a pointer to the DtD to search
2893 * @elem: the element name
2894 * @name: the attribute name
2895 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002896 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00002897 * this element.
2898 *
2899 * returns the xmlAttributePtr if found or NULL
2900 */
2901
2902xmlAttributePtr
2903xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
2904 xmlAttributeTablePtr table;
2905 xmlAttributePtr cur;
2906 xmlChar *uqname = NULL, *prefix = NULL;
2907
2908 if (dtd == NULL) return(NULL);
2909 if (dtd->attributes == NULL) return(NULL);
2910
2911 table = (xmlAttributeTablePtr) dtd->attributes;
2912 if (table == NULL)
2913 return(NULL);
2914
2915 uqname = xmlSplitQName2(name, &prefix);
2916
2917 if (uqname != NULL) {
2918 cur = xmlHashLookup3(table, uqname, prefix, elem);
2919 if (prefix != NULL) xmlFree(prefix);
2920 if (uqname != NULL) xmlFree(uqname);
2921 } else
2922 cur = xmlHashLookup3(table, name, NULL, elem);
2923 return(cur);
2924}
2925
2926/**
2927 * xmlGetDtdQAttrDesc:
2928 * @dtd: a pointer to the DtD to search
2929 * @elem: the element name
2930 * @name: the attribute name
2931 * @prefix: the attribute namespace prefix
2932 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002933 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00002934 * this element.
2935 *
2936 * returns the xmlAttributePtr if found or NULL
2937 */
2938
Daniel Veillard48da9102001-08-07 01:10:10 +00002939xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002940xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
2941 const xmlChar *prefix) {
2942 xmlAttributeTablePtr table;
2943
2944 if (dtd == NULL) return(NULL);
2945 if (dtd->attributes == NULL) return(NULL);
2946 table = (xmlAttributeTablePtr) dtd->attributes;
2947
2948 return(xmlHashLookup3(table, name, prefix, elem));
2949}
2950
2951/**
2952 * xmlGetDtdNotationDesc:
2953 * @dtd: a pointer to the DtD to search
2954 * @name: the notation name
2955 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002956 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00002957 *
2958 * returns the xmlNotationPtr if found or NULL
2959 */
2960
2961xmlNotationPtr
2962xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
2963 xmlNotationTablePtr table;
2964
2965 if (dtd == NULL) return(NULL);
2966 if (dtd->notations == NULL) return(NULL);
2967 table = (xmlNotationTablePtr) dtd->notations;
2968
2969 return(xmlHashLookup(table, name));
2970}
2971
Daniel Veillard4432df22003-09-28 18:58:27 +00002972#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002973/**
2974 * xmlValidateNotationUse:
2975 * @ctxt: the validation context
2976 * @doc: the document
2977 * @notationName: the notation name to check
2978 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002979 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00002980 * - [ VC: Notation Declared ]
2981 *
2982 * returns 1 if valid or 0 otherwise
2983 */
2984
2985int
2986xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2987 const xmlChar *notationName) {
2988 xmlNotationPtr notaDecl;
2989 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2990
2991 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2992 if ((notaDecl == NULL) && (doc->extSubset != NULL))
2993 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2994
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002995 if ((notaDecl == NULL) && (ctxt != NULL)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002996 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2997 notationName);
2998 return(0);
2999 }
3000 return(1);
3001}
Daniel Veillard4432df22003-09-28 18:58:27 +00003002#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003003
3004/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003005 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003006 * @doc: the document
3007 * @name: the element name
3008 *
3009 * Search in the DtDs whether an element accept Mixed content (or ANY)
3010 * basically if it is supposed to accept text childs
3011 *
3012 * returns 0 if no, 1 if yes, and -1 if no element description is available
3013 */
3014
3015int
3016xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3017 xmlElementPtr elemDecl;
3018
3019 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3020
3021 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3022 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3023 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3024 if (elemDecl == NULL) return(-1);
3025 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003026 case XML_ELEMENT_TYPE_UNDEFINED:
3027 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003028 case XML_ELEMENT_TYPE_ELEMENT:
3029 return(0);
3030 case XML_ELEMENT_TYPE_EMPTY:
3031 /*
3032 * return 1 for EMPTY since we want VC error to pop up
3033 * on <empty> </empty> for example
3034 */
3035 case XML_ELEMENT_TYPE_ANY:
3036 case XML_ELEMENT_TYPE_MIXED:
3037 return(1);
3038 }
3039 return(1);
3040}
3041
Daniel Veillard4432df22003-09-28 18:58:27 +00003042#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003043/**
3044 * xmlValidateNameValue:
3045 * @value: an Name value
3046 *
3047 * Validate that the given value match Name production
3048 *
3049 * returns 1 if valid or 0 otherwise
3050 */
3051
Daniel Veillard9b731d72002-04-14 12:56:08 +00003052int
Owen Taylor3473f882001-02-23 17:55:21 +00003053xmlValidateNameValue(const xmlChar *value) {
3054 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003055 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003056
3057 if (value == NULL) return(0);
3058 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003059 val = xmlStringCurrentChar(NULL, cur, &len);
3060 cur += len;
3061 if (!IS_LETTER(val) && (val != '_') &&
3062 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003063 return(0);
3064 }
3065
Daniel Veillardd8224e02002-01-13 15:43:22 +00003066 val = xmlStringCurrentChar(NULL, cur, &len);
3067 cur += len;
3068 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3069 (val == '.') || (val == '-') ||
3070 (val == '_') || (val == ':') ||
3071 (IS_COMBINING(val)) ||
3072 (IS_EXTENDER(val))) {
3073 val = xmlStringCurrentChar(NULL, cur, &len);
3074 cur += len;
3075 }
Owen Taylor3473f882001-02-23 17:55:21 +00003076
Daniel Veillardd8224e02002-01-13 15:43:22 +00003077 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003078
3079 return(1);
3080}
3081
3082/**
3083 * xmlValidateNamesValue:
3084 * @value: an Names value
3085 *
3086 * Validate that the given value match Names production
3087 *
3088 * returns 1 if valid or 0 otherwise
3089 */
3090
Daniel Veillard9b731d72002-04-14 12:56:08 +00003091int
Owen Taylor3473f882001-02-23 17:55:21 +00003092xmlValidateNamesValue(const xmlChar *value) {
3093 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003094 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003095
3096 if (value == NULL) return(0);
3097 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003098 val = xmlStringCurrentChar(NULL, cur, &len);
3099 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003100
Daniel Veillardd8224e02002-01-13 15:43:22 +00003101 if (!IS_LETTER(val) && (val != '_') &&
3102 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003103 return(0);
3104 }
3105
Daniel Veillardd8224e02002-01-13 15:43:22 +00003106 val = xmlStringCurrentChar(NULL, cur, &len);
3107 cur += len;
3108 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3109 (val == '.') || (val == '-') ||
3110 (val == '_') || (val == ':') ||
3111 (IS_COMBINING(val)) ||
3112 (IS_EXTENDER(val))) {
3113 val = xmlStringCurrentChar(NULL, cur, &len);
3114 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003115 }
3116
Daniel Veillardd8224e02002-01-13 15:43:22 +00003117 while (IS_BLANK(val)) {
3118 while (IS_BLANK(val)) {
3119 val = xmlStringCurrentChar(NULL, cur, &len);
3120 cur += len;
3121 }
3122
3123 if (!IS_LETTER(val) && (val != '_') &&
3124 (val != ':')) {
3125 return(0);
3126 }
3127 val = xmlStringCurrentChar(NULL, cur, &len);
3128 cur += len;
3129
3130 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3131 (val == '.') || (val == '-') ||
3132 (val == '_') || (val == ':') ||
3133 (IS_COMBINING(val)) ||
3134 (IS_EXTENDER(val))) {
3135 val = xmlStringCurrentChar(NULL, cur, &len);
3136 cur += len;
3137 }
3138 }
3139
3140 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003141
3142 return(1);
3143}
3144
3145/**
3146 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003147 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003148 *
3149 * Validate that the given value match Nmtoken production
3150 *
3151 * [ VC: Name Token ]
3152 *
3153 * returns 1 if valid or 0 otherwise
3154 */
3155
Daniel Veillard9b731d72002-04-14 12:56:08 +00003156int
Owen Taylor3473f882001-02-23 17:55:21 +00003157xmlValidateNmtokenValue(const xmlChar *value) {
3158 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003159 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003160
3161 if (value == NULL) return(0);
3162 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003163 val = xmlStringCurrentChar(NULL, cur, &len);
3164 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003165
Daniel Veillardd8224e02002-01-13 15:43:22 +00003166 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3167 (val != '.') && (val != '-') &&
3168 (val != '_') && (val != ':') &&
3169 (!IS_COMBINING(val)) &&
3170 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003171 return(0);
3172
Daniel Veillardd8224e02002-01-13 15:43:22 +00003173 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3174 (val == '.') || (val == '-') ||
3175 (val == '_') || (val == ':') ||
3176 (IS_COMBINING(val)) ||
3177 (IS_EXTENDER(val))) {
3178 val = xmlStringCurrentChar(NULL, cur, &len);
3179 cur += len;
3180 }
Owen Taylor3473f882001-02-23 17:55:21 +00003181
Daniel Veillardd8224e02002-01-13 15:43:22 +00003182 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003183
3184 return(1);
3185}
3186
3187/**
3188 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003189 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003190 *
3191 * Validate that the given value match Nmtokens production
3192 *
3193 * [ VC: Name Token ]
3194 *
3195 * returns 1 if valid or 0 otherwise
3196 */
3197
Daniel Veillard9b731d72002-04-14 12:56:08 +00003198int
Owen Taylor3473f882001-02-23 17:55:21 +00003199xmlValidateNmtokensValue(const xmlChar *value) {
3200 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003201 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003202
3203 if (value == NULL) return(0);
3204 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003205 val = xmlStringCurrentChar(NULL, cur, &len);
3206 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003207
Daniel Veillardd8224e02002-01-13 15:43:22 +00003208 while (IS_BLANK(val)) {
3209 val = xmlStringCurrentChar(NULL, cur, &len);
3210 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003211 }
3212
Daniel Veillardd8224e02002-01-13 15:43:22 +00003213 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3214 (val != '.') && (val != '-') &&
3215 (val != '_') && (val != ':') &&
3216 (!IS_COMBINING(val)) &&
3217 (!IS_EXTENDER(val)))
3218 return(0);
3219
3220 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3221 (val == '.') || (val == '-') ||
3222 (val == '_') || (val == ':') ||
3223 (IS_COMBINING(val)) ||
3224 (IS_EXTENDER(val))) {
3225 val = xmlStringCurrentChar(NULL, cur, &len);
3226 cur += len;
3227 }
3228
3229 while (IS_BLANK(val)) {
3230 while (IS_BLANK(val)) {
3231 val = xmlStringCurrentChar(NULL, cur, &len);
3232 cur += len;
3233 }
3234 if (val == 0) return(1);
3235
3236 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3237 (val != '.') && (val != '-') &&
3238 (val != '_') && (val != ':') &&
3239 (!IS_COMBINING(val)) &&
3240 (!IS_EXTENDER(val)))
3241 return(0);
3242
3243 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3244 (val == '.') || (val == '-') ||
3245 (val == '_') || (val == ':') ||
3246 (IS_COMBINING(val)) ||
3247 (IS_EXTENDER(val))) {
3248 val = xmlStringCurrentChar(NULL, cur, &len);
3249 cur += len;
3250 }
3251 }
3252
3253 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003254
3255 return(1);
3256}
3257
3258/**
3259 * xmlValidateNotationDecl:
3260 * @ctxt: the validation context
3261 * @doc: a document instance
3262 * @nota: a notation definition
3263 *
3264 * Try to validate a single notation definition
3265 * basically it does the following checks as described by the
3266 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003267 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003268 * But this function get called anyway ...
3269 *
3270 * returns 1 if valid or 0 otherwise
3271 */
3272
3273int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003274xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3275 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003276 int ret = 1;
3277
3278 return(ret);
3279}
3280
3281/**
3282 * xmlValidateAttributeValue:
3283 * @type: an attribute type
3284 * @value: an attribute value
3285 *
3286 * Validate that the given attribute value match the proper production
3287 *
3288 * [ VC: ID ]
3289 * Values of type ID must match the Name production....
3290 *
3291 * [ VC: IDREF ]
3292 * Values of type IDREF must match the Name production, and values
3293 * of type IDREFS must match Names ...
3294 *
3295 * [ VC: Entity Name ]
3296 * Values of type ENTITY must match the Name production, values
3297 * of type ENTITIES must match Names ...
3298 *
3299 * [ VC: Name Token ]
3300 * Values of type NMTOKEN must match the Nmtoken production; values
3301 * of type NMTOKENS must match Nmtokens.
3302 *
3303 * returns 1 if valid or 0 otherwise
3304 */
3305
3306int
3307xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3308 switch (type) {
3309 case XML_ATTRIBUTE_ENTITIES:
3310 case XML_ATTRIBUTE_IDREFS:
3311 return(xmlValidateNamesValue(value));
3312 case XML_ATTRIBUTE_ENTITY:
3313 case XML_ATTRIBUTE_IDREF:
3314 case XML_ATTRIBUTE_ID:
3315 case XML_ATTRIBUTE_NOTATION:
3316 return(xmlValidateNameValue(value));
3317 case XML_ATTRIBUTE_NMTOKENS:
3318 case XML_ATTRIBUTE_ENUMERATION:
3319 return(xmlValidateNmtokensValue(value));
3320 case XML_ATTRIBUTE_NMTOKEN:
3321 return(xmlValidateNmtokenValue(value));
3322 case XML_ATTRIBUTE_CDATA:
3323 break;
3324 }
3325 return(1);
3326}
3327
3328/**
3329 * xmlValidateAttributeValue2:
3330 * @ctxt: the validation context
3331 * @doc: the document
3332 * @name: the attribute name (used for error reporting only)
3333 * @type: the attribute type
3334 * @value: the attribute value
3335 *
3336 * Validate that the given attribute value match a given type.
3337 * This typically cannot be done before having finished parsing
3338 * the subsets.
3339 *
3340 * [ VC: IDREF ]
3341 * Values of type IDREF must match one of the declared IDs
3342 * Values of type IDREFS must match a sequence of the declared IDs
3343 * each Name must match the value of an ID attribute on some element
3344 * in the XML document; i.e. IDREF values must match the value of
3345 * some ID attribute
3346 *
3347 * [ VC: Entity Name ]
3348 * Values of type ENTITY must match one declared entity
3349 * Values of type ENTITIES must match a sequence of declared entities
3350 *
3351 * [ VC: Notation Attributes ]
3352 * all notation names in the declaration must be declared.
3353 *
3354 * returns 1 if valid or 0 otherwise
3355 */
3356
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003357static int
Owen Taylor3473f882001-02-23 17:55:21 +00003358xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3359 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3360 int ret = 1;
3361 switch (type) {
3362 case XML_ATTRIBUTE_IDREFS:
3363 case XML_ATTRIBUTE_IDREF:
3364 case XML_ATTRIBUTE_ID:
3365 case XML_ATTRIBUTE_NMTOKENS:
3366 case XML_ATTRIBUTE_ENUMERATION:
3367 case XML_ATTRIBUTE_NMTOKEN:
3368 case XML_ATTRIBUTE_CDATA:
3369 break;
3370 case XML_ATTRIBUTE_ENTITY: {
3371 xmlEntityPtr ent;
3372
3373 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003374 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003375 if ((ent == NULL) && (doc->standalone == 1)) {
3376 doc->standalone = 0;
3377 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003378 }
Owen Taylor3473f882001-02-23 17:55:21 +00003379 if (ent == NULL) {
3380 VERROR(ctxt->userData,
3381 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3382 name, value);
3383 ret = 0;
3384 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3385 VERROR(ctxt->userData,
3386 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3387 name, value);
3388 ret = 0;
3389 }
3390 break;
3391 }
3392 case XML_ATTRIBUTE_ENTITIES: {
3393 xmlChar *dup, *nam = NULL, *cur, save;
3394 xmlEntityPtr ent;
3395
3396 dup = xmlStrdup(value);
3397 if (dup == NULL)
3398 return(0);
3399 cur = dup;
3400 while (*cur != 0) {
3401 nam = cur;
3402 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3403 save = *cur;
3404 *cur = 0;
3405 ent = xmlGetDocEntity(doc, nam);
3406 if (ent == NULL) {
3407 VERROR(ctxt->userData,
3408 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
3409 name, nam);
3410 ret = 0;
3411 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3412 VERROR(ctxt->userData,
3413 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
3414 name, nam);
3415 ret = 0;
3416 }
3417 if (save == 0)
3418 break;
3419 *cur = save;
3420 while (IS_BLANK(*cur)) cur++;
3421 }
3422 xmlFree(dup);
3423 break;
3424 }
3425 case XML_ATTRIBUTE_NOTATION: {
3426 xmlNotationPtr nota;
3427
3428 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3429 if ((nota == NULL) && (doc->extSubset != NULL))
3430 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3431
3432 if (nota == NULL) {
3433 VERROR(ctxt->userData,
3434 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
3435 name, value);
3436 ret = 0;
3437 }
3438 break;
3439 }
3440 }
3441 return(ret);
3442}
3443
3444/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003445 * xmlValidCtxtNormalizeAttributeValue:
3446 * @ctxt: the validation context
3447 * @doc: the document
3448 * @elem: the parent
3449 * @name: the attribute name
3450 * @value: the attribute value
3451 * @ctxt: the validation context or NULL
3452 *
3453 * Does the validation related extra step of the normalization of attribute
3454 * values:
3455 *
3456 * If the declared value is not CDATA, then the XML processor must further
3457 * process the normalized attribute value by discarding any leading and
3458 * trailing space (#x20) characters, and by replacing sequences of space
3459 * (#x20) characters by single space (#x20) character.
3460 *
3461 * Also check VC: Standalone Document Declaration in P32, and update
3462 * ctxt->valid accordingly
3463 *
3464 * returns a new normalized string if normalization is needed, NULL otherwise
3465 * the caller must free the returned value.
3466 */
3467
3468xmlChar *
3469xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3470 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3471 xmlChar *ret, *dst;
3472 const xmlChar *src;
3473 xmlAttributePtr attrDecl = NULL;
3474 int extsubset = 0;
3475
3476 if (doc == NULL) return(NULL);
3477 if (elem == NULL) return(NULL);
3478 if (name == NULL) return(NULL);
3479 if (value == NULL) return(NULL);
3480
3481 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003482 xmlChar fn[50];
3483 xmlChar *fullname;
3484
3485 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3486 if (fullname == NULL)
3487 return(0);
3488 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003489 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003490 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003491 if (attrDecl != NULL)
3492 extsubset = 1;
3493 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003494 if ((fullname != fn) && (fullname != elem->name))
3495 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003496 }
3497 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3498 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3499 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3500 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3501 if (attrDecl != NULL)
3502 extsubset = 1;
3503 }
3504
3505 if (attrDecl == NULL)
3506 return(NULL);
3507 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3508 return(NULL);
3509
3510 ret = xmlStrdup(value);
3511 if (ret == NULL)
3512 return(NULL);
3513 src = value;
3514 dst = ret;
3515 while (*src == 0x20) src++;
3516 while (*src != 0) {
3517 if (*src == 0x20) {
3518 while (*src == 0x20) src++;
3519 if (*src != 0)
3520 *dst++ = 0x20;
3521 } else {
3522 *dst++ = *src++;
3523 }
3524 }
3525 *dst = 0;
3526 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
3527 VERROR(ctxt->userData,
3528"standalone: %s on %s value had to be normalized based on external subset declaration\n",
3529 name, elem->name);
3530 ctxt->valid = 0;
3531 }
3532 return(ret);
3533}
3534
3535/**
Owen Taylor3473f882001-02-23 17:55:21 +00003536 * xmlValidNormalizeAttributeValue:
3537 * @doc: the document
3538 * @elem: the parent
3539 * @name: the attribute name
3540 * @value: the attribute value
3541 *
3542 * Does the validation related extra step of the normalization of attribute
3543 * values:
3544 *
3545 * If the declared value is not CDATA, then the XML processor must further
3546 * process the normalized attribute value by discarding any leading and
3547 * trailing space (#x20) characters, and by replacing sequences of space
3548 * (#x20) characters by single space (#x20) character.
3549 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003550 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003551 * the caller must free the returned value.
3552 */
3553
3554xmlChar *
3555xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3556 const xmlChar *name, const xmlChar *value) {
3557 xmlChar *ret, *dst;
3558 const xmlChar *src;
3559 xmlAttributePtr attrDecl = NULL;
3560
3561 if (doc == NULL) return(NULL);
3562 if (elem == NULL) return(NULL);
3563 if (name == NULL) return(NULL);
3564 if (value == NULL) return(NULL);
3565
3566 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003567 xmlChar fn[50];
3568 xmlChar *fullname;
3569
3570 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3571 if (fullname == NULL)
3572 return(0);
3573 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003574 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003575 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3576 if ((fullname != fn) && (fullname != elem->name))
3577 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003578 }
3579 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3580 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3581 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3582
3583 if (attrDecl == NULL)
3584 return(NULL);
3585 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3586 return(NULL);
3587
3588 ret = xmlStrdup(value);
3589 if (ret == NULL)
3590 return(NULL);
3591 src = value;
3592 dst = ret;
3593 while (*src == 0x20) src++;
3594 while (*src != 0) {
3595 if (*src == 0x20) {
3596 while (*src == 0x20) src++;
3597 if (*src != 0)
3598 *dst++ = 0x20;
3599 } else {
3600 *dst++ = *src++;
3601 }
3602 }
3603 *dst = 0;
3604 return(ret);
3605}
3606
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003607static void
Owen Taylor3473f882001-02-23 17:55:21 +00003608xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003609 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003610 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3611}
3612
3613/**
3614 * xmlValidateAttributeDecl:
3615 * @ctxt: the validation context
3616 * @doc: a document instance
3617 * @attr: an attribute definition
3618 *
3619 * Try to validate a single attribute definition
3620 * basically it does the following checks as described by the
3621 * XML-1.0 recommendation:
3622 * - [ VC: Attribute Default Legal ]
3623 * - [ VC: Enumeration ]
3624 * - [ VC: ID Attribute Default ]
3625 *
3626 * The ID/IDREF uniqueness and matching are done separately
3627 *
3628 * returns 1 if valid or 0 otherwise
3629 */
3630
3631int
3632xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3633 xmlAttributePtr attr) {
3634 int ret = 1;
3635 int val;
3636 CHECK_DTD;
3637 if(attr == NULL) return(1);
3638
3639 /* Attribute Default Legal */
3640 /* Enumeration */
3641 if (attr->defaultValue != NULL) {
3642 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3643 if (val == 0) {
3644 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003645 "Syntax of default value for attribute %s of %s is not valid\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003646 attr->name, attr->elem);
3647 }
3648 ret &= val;
3649 }
3650
3651 /* ID Attribute Default */
3652 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3653 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3654 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
3655 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003656 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003657 attr->name, attr->elem);
3658 ret = 0;
3659 }
3660
3661 /* One ID per Element Type */
3662 if (attr->atype == XML_ATTRIBUTE_ID) {
3663 int nbId;
3664
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003665 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00003666 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3667 attr->elem);
3668 if (elem != NULL) {
3669 nbId = xmlScanIDAttributeDecl(NULL, elem);
3670 } else {
3671 xmlAttributeTablePtr table;
3672
3673 /*
3674 * The attribute may be declared in the internal subset and the
3675 * element in the external subset.
3676 */
3677 nbId = 0;
3678 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3679 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3680 xmlValidateAttributeIdCallback, &nbId);
3681 }
3682 if (nbId > 1) {
3683 VERROR(ctxt->userData,
3684 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3685 attr->elem, nbId, attr->name);
3686 } else if (doc->extSubset != NULL) {
3687 int extId = 0;
3688 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3689 if (elem != NULL) {
3690 extId = xmlScanIDAttributeDecl(NULL, elem);
3691 }
3692 if (extId > 1) {
3693 VERROR(ctxt->userData,
3694 "Element %s has %d ID attribute defined in the external subset : %s\n",
3695 attr->elem, extId, attr->name);
3696 } else if (extId + nbId > 1) {
3697 VERROR(ctxt->userData,
3698"Element %s has ID attributes defined in the internal and external subset : %s\n",
3699 attr->elem, attr->name);
3700 }
3701 }
3702 }
3703
3704 /* Validity Constraint: Enumeration */
3705 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3706 xmlEnumerationPtr tree = attr->tree;
3707 while (tree != NULL) {
3708 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3709 tree = tree->next;
3710 }
3711 if (tree == NULL) {
3712 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003713"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003714 attr->defaultValue, attr->name, attr->elem);
3715 ret = 0;
3716 }
3717 }
3718
3719 return(ret);
3720}
3721
3722/**
3723 * xmlValidateElementDecl:
3724 * @ctxt: the validation context
3725 * @doc: a document instance
3726 * @elem: an element definition
3727 *
3728 * Try to validate a single element definition
3729 * basically it does the following checks as described by the
3730 * XML-1.0 recommendation:
3731 * - [ VC: One ID per Element Type ]
3732 * - [ VC: No Duplicate Types ]
3733 * - [ VC: Unique Element Type Declaration ]
3734 *
3735 * returns 1 if valid or 0 otherwise
3736 */
3737
3738int
3739xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3740 xmlElementPtr elem) {
3741 int ret = 1;
3742 xmlElementPtr tst;
3743
3744 CHECK_DTD;
3745
3746 if (elem == NULL) return(1);
3747
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003748#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00003749#ifdef LIBXML_REGEXP_ENABLED
3750 /* Build the regexp associated to the content model */
3751 ret = xmlValidBuildContentModel(ctxt, elem);
3752#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003753#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00003754
Owen Taylor3473f882001-02-23 17:55:21 +00003755 /* No Duplicate Types */
3756 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3757 xmlElementContentPtr cur, next;
3758 const xmlChar *name;
3759
3760 cur = elem->content;
3761 while (cur != NULL) {
3762 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3763 if (cur->c1 == NULL) break;
3764 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3765 name = cur->c1->name;
3766 next = cur->c2;
3767 while (next != NULL) {
3768 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00003769 if ((xmlStrEqual(next->name, name)) &&
3770 (xmlStrEqual(next->prefix, cur->prefix))) {
3771 if (cur->prefix == NULL) {
3772 VERROR(ctxt->userData,
Owen Taylor3473f882001-02-23 17:55:21 +00003773 "Definition of %s has duplicate references of %s\n",
Daniel Veillard7b68df92003-08-03 22:58:54 +00003774 elem->name, name);
3775 } else {
3776 VERROR(ctxt->userData,
3777 "Definition of %s has duplicate references of %s:%s\n",
3778 elem->name, cur->prefix, name);
3779 }
Owen Taylor3473f882001-02-23 17:55:21 +00003780 ret = 0;
3781 }
3782 break;
3783 }
3784 if (next->c1 == NULL) break;
3785 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00003786 if ((xmlStrEqual(next->c1->name, name)) &&
3787 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
3788 if (cur->prefix == NULL) {
3789 VERROR(ctxt->userData,
3790 "Definition of %s has duplicate references to %s\n",
3791 elem->name, name);
3792 } else {
3793 VERROR(ctxt->userData,
3794 "Definition of %s has duplicate references to %s:%s\n",
3795 elem->name, cur->prefix, name);
3796 }
Owen Taylor3473f882001-02-23 17:55:21 +00003797 ret = 0;
3798 }
3799 next = next->c2;
3800 }
3801 }
3802 cur = cur->c2;
3803 }
3804 }
3805
3806 /* VC: Unique Element Type Declaration */
3807 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003808 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00003809 ((tst->prefix == elem->prefix) ||
3810 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00003811 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003812 VERROR(ctxt->userData, "Redefinition of element %s\n",
3813 elem->name);
3814 ret = 0;
3815 }
3816 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003817 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00003818 ((tst->prefix == elem->prefix) ||
3819 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00003820 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003821 VERROR(ctxt->userData, "Redefinition of element %s\n",
3822 elem->name);
3823 ret = 0;
3824 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00003825 /* One ID per Element Type
3826 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00003827 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3828 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00003829 } */
Owen Taylor3473f882001-02-23 17:55:21 +00003830 return(ret);
3831}
3832
3833/**
3834 * xmlValidateOneAttribute:
3835 * @ctxt: the validation context
3836 * @doc: a document instance
3837 * @elem: an element instance
3838 * @attr: an attribute instance
3839 * @value: the attribute value (without entities processing)
3840 *
3841 * Try to validate a single attribute for an element
3842 * basically it does the following checks as described by the
3843 * XML-1.0 recommendation:
3844 * - [ VC: Attribute Value Type ]
3845 * - [ VC: Fixed Attribute Default ]
3846 * - [ VC: Entity Name ]
3847 * - [ VC: Name Token ]
3848 * - [ VC: ID ]
3849 * - [ VC: IDREF ]
3850 * - [ VC: Entity Name ]
3851 * - [ VC: Notation Attributes ]
3852 *
3853 * The ID/IDREF uniqueness and matching are done separately
3854 *
3855 * returns 1 if valid or 0 otherwise
3856 */
3857
3858int
3859xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00003860 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
3861{
Owen Taylor3473f882001-02-23 17:55:21 +00003862 xmlAttributePtr attrDecl = NULL;
3863 int val;
3864 int ret = 1;
3865
3866 CHECK_DTD;
3867 if ((elem == NULL) || (elem->name == NULL)) return(0);
3868 if ((attr == NULL) || (attr->name == NULL)) return(0);
3869
3870 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003871 xmlChar fn[50];
3872 xmlChar *fullname;
3873
3874 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3875 if (fullname == NULL)
3876 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003877 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003878 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00003879 attr->name, attr->ns->prefix);
3880 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003881 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00003882 attr->name, attr->ns->prefix);
3883 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003884 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00003885 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3886 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00003887 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00003888 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003889 if ((fullname != fn) && (fullname != elem->name))
3890 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003891 }
3892 if (attrDecl == NULL) {
3893 if (attr->ns != NULL) {
3894 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
3895 attr->name, attr->ns->prefix);
3896 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3897 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
3898 attr->name, attr->ns->prefix);
3899 } else {
3900 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
3901 elem->name, attr->name);
3902 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3903 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3904 elem->name, attr->name);
3905 }
3906 }
3907
3908
3909 /* Validity Constraint: Attribute Value Type */
3910 if (attrDecl == NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00003911 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003912 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003913 "No declaration for attribute %s of element %s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003914 attr->name, elem->name);
3915 return(0);
3916 }
3917 attr->atype = attrDecl->atype;
3918
3919 val = xmlValidateAttributeValue(attrDecl->atype, value);
3920 if (val == 0) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00003921 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003922 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003923 "Syntax of value for attribute %s of %s is not valid\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003924 attr->name, elem->name);
3925 ret = 0;
3926 }
3927
3928 /* Validity constraint: Fixed Attribute Default */
3929 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
3930 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00003931 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003932 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003933 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003934 attr->name, elem->name, attrDecl->defaultValue);
3935 ret = 0;
3936 }
3937 }
3938
3939 /* Validity Constraint: ID uniqueness */
3940 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
3941 if (xmlAddID(ctxt, doc, value, attr) == NULL)
3942 ret = 0;
3943 }
3944
3945 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
3946 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
3947 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
3948 ret = 0;
3949 }
3950
3951 /* Validity Constraint: Notation Attributes */
3952 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
3953 xmlEnumerationPtr tree = attrDecl->tree;
3954 xmlNotationPtr nota;
3955
3956 /* First check that the given NOTATION was declared */
3957 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3958 if (nota == NULL)
3959 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3960
3961 if (nota == NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00003962 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003963 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003964 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003965 value, attr->name, elem->name);
3966 ret = 0;
3967 }
3968
3969 /* Second, verify that it's among the list */
3970 while (tree != NULL) {
3971 if (xmlStrEqual(tree->name, value)) break;
3972 tree = tree->next;
3973 }
3974 if (tree == NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00003975 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003976 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003977"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003978 value, attr->name, elem->name);
3979 ret = 0;
3980 }
3981 }
3982
3983 /* Validity Constraint: Enumeration */
3984 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
3985 xmlEnumerationPtr tree = attrDecl->tree;
3986 while (tree != NULL) {
3987 if (xmlStrEqual(tree->name, value)) break;
3988 tree = tree->next;
3989 }
3990 if (tree == NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00003991 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00003992 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003993 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003994 value, attr->name, elem->name);
3995 ret = 0;
3996 }
3997 }
3998
3999 /* Fixed Attribute Default */
4000 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4001 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004002 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00004003 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004004 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004005 attr->name, elem->name, attrDecl->defaultValue);
4006 ret = 0;
4007 }
4008
4009 /* Extra check for the attribute value */
4010 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4011 attrDecl->atype, value);
4012
4013 return(ret);
4014}
4015
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004016/**
4017 * xmlValidateOneNamespace:
4018 * @ctxt: the validation context
4019 * @doc: a document instance
4020 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004021 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004022 * @ns: an namespace declaration instance
4023 * @value: the attribute value (without entities processing)
4024 *
4025 * Try to validate a single namespace declaration for an element
4026 * basically it does the following checks as described by the
4027 * XML-1.0 recommendation:
4028 * - [ VC: Attribute Value Type ]
4029 * - [ VC: Fixed Attribute Default ]
4030 * - [ VC: Entity Name ]
4031 * - [ VC: Name Token ]
4032 * - [ VC: ID ]
4033 * - [ VC: IDREF ]
4034 * - [ VC: Entity Name ]
4035 * - [ VC: Notation Attributes ]
4036 *
4037 * The ID/IDREF uniqueness and matching are done separately
4038 *
4039 * returns 1 if valid or 0 otherwise
4040 */
4041
4042int
4043xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4044xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4045 /* xmlElementPtr elemDecl; */
4046 xmlAttributePtr attrDecl = NULL;
4047 int val;
4048 int ret = 1;
4049
4050 CHECK_DTD;
4051 if ((elem == NULL) || (elem->name == NULL)) return(0);
4052 if ((ns == NULL) || (ns->href == NULL)) return(0);
4053
4054 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004055 xmlChar fn[50];
4056 xmlChar *fullname;
4057
4058 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4059 if (fullname == NULL) {
4060 VERROR(ctxt->userData, "Out of memory\n");
4061 return(0);
4062 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004063 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004064 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004065 ns->prefix, BAD_CAST "xmlns");
4066 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004067 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004068 ns->prefix, BAD_CAST "xmlns");
4069 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004070 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004071 BAD_CAST "xmlns");
4072 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004073 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004074 BAD_CAST "xmlns");
4075 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004076 if ((fullname != fn) && (fullname != elem->name))
4077 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004078 }
4079 if (attrDecl == NULL) {
4080 if (ns->prefix != NULL) {
4081 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4082 ns->prefix, BAD_CAST "xmlns");
4083 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4084 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4085 ns->prefix, BAD_CAST "xmlns");
4086 } else {
4087 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4088 elem->name, BAD_CAST "xmlns");
4089 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4090 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4091 elem->name, BAD_CAST "xmlns");
4092 }
4093 }
4094
4095
4096 /* Validity Constraint: Attribute Value Type */
4097 if (attrDecl == NULL) {
4098 VECTXT(ctxt, elem);
4099 if (ns->prefix != NULL) {
4100 VERROR(ctxt->userData,
4101 "No declaration for attribute xmlns:%s of element %s\n",
4102 ns->prefix, elem->name);
4103 } else {
4104 VERROR(ctxt->userData,
4105 "No declaration for attribute xmlns of element %s\n",
4106 elem->name);
4107 }
4108 return(0);
4109 }
4110
4111 val = xmlValidateAttributeValue(attrDecl->atype, value);
4112 if (val == 0) {
4113 VECTXT(ctxt, elem);
4114 if (ns->prefix != NULL) {
4115 VERROR(ctxt->userData,
4116 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4117 ns->prefix, elem->name);
4118 } else {
4119 VERROR(ctxt->userData,
4120 "Syntax of value for attribute xmlns of %s is not valid\n",
4121 elem->name);
4122 }
4123 ret = 0;
4124 }
4125
4126 /* Validity constraint: Fixed Attribute Default */
4127 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4128 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4129 VECTXT(ctxt, elem);
4130 if (ns->prefix != NULL) {
4131 VERROR(ctxt->userData,
4132 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4133 ns->prefix, elem->name, attrDecl->defaultValue);
4134 } else {
4135 VERROR(ctxt->userData,
4136 "Value for attribute xmlns of %s is different from default \"%s\"\n",
4137 elem->name, attrDecl->defaultValue);
4138 }
4139 ret = 0;
4140 }
4141 }
4142
4143 /* Validity Constraint: ID uniqueness */
4144 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4145 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4146 ret = 0;
4147 }
4148
4149 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4150 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4151 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4152 ret = 0;
4153 }
4154
4155 /* Validity Constraint: Notation Attributes */
4156 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4157 xmlEnumerationPtr tree = attrDecl->tree;
4158 xmlNotationPtr nota;
4159
4160 /* First check that the given NOTATION was declared */
4161 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4162 if (nota == NULL)
4163 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4164
4165 if (nota == NULL) {
4166 VECTXT(ctxt, elem);
4167 if (ns->prefix != NULL) {
4168 VERROR(ctxt->userData,
4169 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4170 value, ns->prefix, elem->name);
4171 } else {
4172 VERROR(ctxt->userData,
4173 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4174 value, elem->name);
4175 }
4176 ret = 0;
4177 }
4178
4179 /* Second, verify that it's among the list */
4180 while (tree != NULL) {
4181 if (xmlStrEqual(tree->name, value)) break;
4182 tree = tree->next;
4183 }
4184 if (tree == NULL) {
4185 VECTXT(ctxt, elem);
4186 if (ns->prefix != NULL) {
4187 VERROR(ctxt->userData,
4188"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4189 value, ns->prefix, elem->name);
4190 } else {
4191 VERROR(ctxt->userData,
4192"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4193 value, elem->name);
4194 }
4195 ret = 0;
4196 }
4197 }
4198
4199 /* Validity Constraint: Enumeration */
4200 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4201 xmlEnumerationPtr tree = attrDecl->tree;
4202 while (tree != NULL) {
4203 if (xmlStrEqual(tree->name, value)) break;
4204 tree = tree->next;
4205 }
4206 if (tree == NULL) {
4207 VECTXT(ctxt, elem);
4208 if (ns->prefix != NULL) {
4209 VERROR(ctxt->userData,
4210"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4211 value, ns->prefix, elem->name);
4212 } else {
4213 VERROR(ctxt->userData,
4214"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4215 value, elem->name);
4216 }
4217 ret = 0;
4218 }
4219 }
4220
4221 /* Fixed Attribute Default */
4222 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4223 (!xmlStrEqual(attrDecl->defaultValue, value))) {
4224 VECTXT(ctxt, elem);
4225 if (ns->prefix != NULL) {
4226 VERROR(ctxt->userData,
4227 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4228 ns->prefix, elem->name, attrDecl->defaultValue);
4229 } else {
4230 VERROR(ctxt->userData,
4231 "Value for attribute xmlns of %s must be \"%s\"\n",
4232 elem->name, attrDecl->defaultValue);
4233 }
4234 ret = 0;
4235 }
4236
4237 /* Extra check for the attribute value */
4238 if (ns->prefix != NULL) {
4239 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4240 attrDecl->atype, value);
4241 } else {
4242 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4243 attrDecl->atype, value);
4244 }
4245
4246 return(ret);
4247}
4248
Daniel Veillard118aed72002-09-24 14:13:13 +00004249#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004250/**
4251 * xmlValidateSkipIgnorable:
4252 * @ctxt: the validation context
4253 * @child: the child list
4254 *
4255 * Skip ignorable elements w.r.t. the validation process
4256 *
4257 * returns the first element to consider for validation of the content model
4258 */
4259
4260static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004261xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004262 while (child != NULL) {
4263 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004264 /* These things are ignored (skipped) during validation. */
4265 case XML_PI_NODE:
4266 case XML_COMMENT_NODE:
4267 case XML_XINCLUDE_START:
4268 case XML_XINCLUDE_END:
4269 child = child->next;
4270 break;
4271 case XML_TEXT_NODE:
4272 if (xmlIsBlankNode(child))
4273 child = child->next;
4274 else
4275 return(child);
4276 break;
4277 /* keep current node */
4278 default:
4279 return(child);
4280 }
4281 }
4282 return(child);
4283}
4284
4285/**
4286 * xmlValidateElementType:
4287 * @ctxt: the validation context
4288 *
4289 * Try to validate the content model of an element internal function
4290 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004291 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4292 * reference is found and -3 if the validation succeeded but
4293 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004294 */
4295
4296static int
4297xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004298 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004299 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004300
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004301 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004302 if ((NODE == NULL) && (CONT == NULL))
4303 return(1);
4304 if ((NODE == NULL) &&
4305 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4306 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4307 return(1);
4308 }
4309 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004310 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004311 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004312
4313 /*
4314 * We arrive here when more states need to be examined
4315 */
4316cont:
4317
4318 /*
4319 * We just recovered from a rollback generated by a possible
4320 * epsilon transition, go directly to the analysis phase
4321 */
4322 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004323 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004324 DEBUG_VALID_STATE(NODE, CONT)
4325 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004326 goto analyze;
4327 }
4328
4329 DEBUG_VALID_STATE(NODE, CONT)
4330 /*
4331 * we may have to save a backup state here. This is the equivalent
4332 * of handling epsilon transition in NFAs.
4333 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004334 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004335 ((CONT->parent == NULL) ||
4336 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004337 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004338 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004339 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004340 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004341 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4342 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004343 }
4344
4345
4346 /*
4347 * Check first if the content matches
4348 */
4349 switch (CONT->type) {
4350 case XML_ELEMENT_CONTENT_PCDATA:
4351 if (NODE == NULL) {
4352 DEBUG_VALID_MSG("pcdata failed no node");
4353 ret = 0;
4354 break;
4355 }
4356 if (NODE->type == XML_TEXT_NODE) {
4357 DEBUG_VALID_MSG("pcdata found, skip to next");
4358 /*
4359 * go to next element in the content model
4360 * skipping ignorable elems
4361 */
4362 do {
4363 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004364 NODE = xmlValidateSkipIgnorable(NODE);
4365 if ((NODE != NULL) &&
4366 (NODE->type == XML_ENTITY_REF_NODE))
4367 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004368 } while ((NODE != NULL) &&
4369 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004370 (NODE->type != XML_TEXT_NODE) &&
4371 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004372 ret = 1;
4373 break;
4374 } else {
4375 DEBUG_VALID_MSG("pcdata failed");
4376 ret = 0;
4377 break;
4378 }
4379 break;
4380 case XML_ELEMENT_CONTENT_ELEMENT:
4381 if (NODE == NULL) {
4382 DEBUG_VALID_MSG("element failed no node");
4383 ret = 0;
4384 break;
4385 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004386 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4387 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004388 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004389 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4390 ret = (CONT->prefix == NULL);
4391 } else if (CONT->prefix == NULL) {
4392 ret = 0;
4393 } else {
4394 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4395 }
4396 }
4397 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004398 DEBUG_VALID_MSG("element found, skip to next");
4399 /*
4400 * go to next element in the content model
4401 * skipping ignorable elems
4402 */
4403 do {
4404 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004405 NODE = xmlValidateSkipIgnorable(NODE);
4406 if ((NODE != NULL) &&
4407 (NODE->type == XML_ENTITY_REF_NODE))
4408 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004409 } while ((NODE != NULL) &&
4410 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004411 (NODE->type != XML_TEXT_NODE) &&
4412 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004413 } else {
4414 DEBUG_VALID_MSG("element failed");
4415 ret = 0;
4416 break;
4417 }
4418 break;
4419 case XML_ELEMENT_CONTENT_OR:
4420 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004421 * Small optimization.
4422 */
4423 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4424 if ((NODE == NULL) ||
4425 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4426 DEPTH++;
4427 CONT = CONT->c2;
4428 goto cont;
4429 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004430 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4431 ret = (CONT->c1->prefix == NULL);
4432 } else if (CONT->c1->prefix == NULL) {
4433 ret = 0;
4434 } else {
4435 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4436 }
4437 if (ret == 0) {
4438 DEPTH++;
4439 CONT = CONT->c2;
4440 goto cont;
4441 }
Daniel Veillard85349052001-04-20 13:48:21 +00004442 }
4443
4444 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004445 * save the second branch 'or' branch
4446 */
4447 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004448 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4449 OCCURS, ROLLBACK_OR) < 0)
4450 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004451 DEPTH++;
4452 CONT = CONT->c1;
4453 goto cont;
4454 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004455 /*
4456 * Small optimization.
4457 */
4458 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4459 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4460 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4461 if ((NODE == NULL) ||
4462 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4463 DEPTH++;
4464 CONT = CONT->c2;
4465 goto cont;
4466 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004467 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4468 ret = (CONT->c1->prefix == NULL);
4469 } else if (CONT->c1->prefix == NULL) {
4470 ret = 0;
4471 } else {
4472 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4473 }
4474 if (ret == 0) {
4475 DEPTH++;
4476 CONT = CONT->c2;
4477 goto cont;
4478 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004479 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004480 DEPTH++;
4481 CONT = CONT->c1;
4482 goto cont;
4483 }
4484
4485 /*
4486 * At this point handle going up in the tree
4487 */
4488 if (ret == -1) {
4489 DEBUG_VALID_MSG("error found returning");
4490 return(ret);
4491 }
4492analyze:
4493 while (CONT != NULL) {
4494 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004495 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004496 * this level.
4497 */
4498 if (ret == 0) {
4499 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004500 xmlNodePtr cur;
4501
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004502 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004503 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004504 DEBUG_VALID_MSG("Once branch failed, rollback");
4505 if (vstateVPop(ctxt) < 0 ) {
4506 DEBUG_VALID_MSG("exhaustion, failed");
4507 return(0);
4508 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004509 if (cur != ctxt->vstate->node)
4510 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004511 goto cont;
4512 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004513 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004514 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004515 DEBUG_VALID_MSG("Plus branch failed, rollback");
4516 if (vstateVPop(ctxt) < 0 ) {
4517 DEBUG_VALID_MSG("exhaustion, failed");
4518 return(0);
4519 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004520 if (cur != ctxt->vstate->node)
4521 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004522 goto cont;
4523 }
4524 DEBUG_VALID_MSG("Plus branch found");
4525 ret = 1;
4526 break;
4527 case XML_ELEMENT_CONTENT_MULT:
4528#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004529 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004530 DEBUG_VALID_MSG("Mult branch failed");
4531 } else {
4532 DEBUG_VALID_MSG("Mult branch found");
4533 }
4534#endif
4535 ret = 1;
4536 break;
4537 case XML_ELEMENT_CONTENT_OPT:
4538 DEBUG_VALID_MSG("Option branch failed");
4539 ret = 1;
4540 break;
4541 }
4542 } else {
4543 switch (CONT->ocur) {
4544 case XML_ELEMENT_CONTENT_OPT:
4545 DEBUG_VALID_MSG("Option branch succeeded");
4546 ret = 1;
4547 break;
4548 case XML_ELEMENT_CONTENT_ONCE:
4549 DEBUG_VALID_MSG("Once branch succeeded");
4550 ret = 1;
4551 break;
4552 case XML_ELEMENT_CONTENT_PLUS:
4553 if (STATE == ROLLBACK_PARENT) {
4554 DEBUG_VALID_MSG("Plus branch rollback");
4555 ret = 1;
4556 break;
4557 }
4558 if (NODE == NULL) {
4559 DEBUG_VALID_MSG("Plus branch exhausted");
4560 ret = 1;
4561 break;
4562 }
4563 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004564 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004565 goto cont;
4566 case XML_ELEMENT_CONTENT_MULT:
4567 if (STATE == ROLLBACK_PARENT) {
4568 DEBUG_VALID_MSG("Mult branch rollback");
4569 ret = 1;
4570 break;
4571 }
4572 if (NODE == NULL) {
4573 DEBUG_VALID_MSG("Mult branch exhausted");
4574 ret = 1;
4575 break;
4576 }
4577 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004578 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004579 goto cont;
4580 }
4581 }
4582 STATE = 0;
4583
4584 /*
4585 * Then act accordingly at the parent level
4586 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004587 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004588 if (CONT->parent == NULL)
4589 break;
4590
4591 switch (CONT->parent->type) {
4592 case XML_ELEMENT_CONTENT_PCDATA:
4593 DEBUG_VALID_MSG("Error: parent pcdata");
4594 return(-1);
4595 case XML_ELEMENT_CONTENT_ELEMENT:
4596 DEBUG_VALID_MSG("Error: parent element");
4597 return(-1);
4598 case XML_ELEMENT_CONTENT_OR:
4599 if (ret == 1) {
4600 DEBUG_VALID_MSG("Or succeeded");
4601 CONT = CONT->parent;
4602 DEPTH--;
4603 } else {
4604 DEBUG_VALID_MSG("Or failed");
4605 CONT = CONT->parent;
4606 DEPTH--;
4607 }
4608 break;
4609 case XML_ELEMENT_CONTENT_SEQ:
4610 if (ret == 0) {
4611 DEBUG_VALID_MSG("Sequence failed");
4612 CONT = CONT->parent;
4613 DEPTH--;
4614 } else if (CONT == CONT->parent->c1) {
4615 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4616 CONT = CONT->parent->c2;
4617 goto cont;
4618 } else {
4619 DEBUG_VALID_MSG("Sequence succeeded");
4620 CONT = CONT->parent;
4621 DEPTH--;
4622 }
4623 }
4624 }
4625 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004626 xmlNodePtr cur;
4627
4628 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004629 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4630 if (vstateVPop(ctxt) < 0 ) {
4631 DEBUG_VALID_MSG("exhaustion, failed");
4632 return(0);
4633 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004634 if (cur != ctxt->vstate->node)
4635 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004636 goto cont;
4637 }
4638 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004639 xmlNodePtr cur;
4640
4641 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004642 DEBUG_VALID_MSG("Failure, rollback");
4643 if (vstateVPop(ctxt) < 0 ) {
4644 DEBUG_VALID_MSG("exhaustion, failed");
4645 return(0);
4646 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004647 if (cur != ctxt->vstate->node)
4648 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004649 goto cont;
4650 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004651 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004652}
Daniel Veillard23e73572002-09-19 19:56:43 +00004653#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004654
4655/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00004656 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004657 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00004658 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004659 * @content: An element
4660 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4661 *
4662 * This will dump the list of elements to the buffer
4663 * Intended just for the debug routine
4664 */
4665static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00004666xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004667 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00004668 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004669
4670 if (node == NULL) return;
4671 if (glob) strcat(buf, "(");
4672 cur = node;
4673 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004674 len = strlen(buf);
4675 if (size - len < 50) {
4676 if ((size - len > 4) && (buf[len - 1] != '.'))
4677 strcat(buf, " ...");
4678 return;
4679 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004680 switch (cur->type) {
4681 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004682 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004683 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004684 if ((size - len > 4) && (buf[len - 1] != '.'))
4685 strcat(buf, " ...");
4686 return;
4687 }
4688 strcat(buf, (char *) cur->ns->prefix);
4689 strcat(buf, ":");
4690 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004691 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004692 if ((size - len > 4) && (buf[len - 1] != '.'))
4693 strcat(buf, " ...");
4694 return;
4695 }
4696 strcat(buf, (char *) cur->name);
4697 if (cur->next != NULL)
4698 strcat(buf, " ");
4699 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004700 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004701 if (xmlIsBlankNode(cur))
4702 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004703 case XML_CDATA_SECTION_NODE:
4704 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004705 strcat(buf, "CDATA");
4706 if (cur->next != NULL)
4707 strcat(buf, " ");
4708 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004709 case XML_ATTRIBUTE_NODE:
4710 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004711#ifdef LIBXML_DOCB_ENABLED
4712 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004713#endif
4714 case XML_HTML_DOCUMENT_NODE:
4715 case XML_DOCUMENT_TYPE_NODE:
4716 case XML_DOCUMENT_FRAG_NODE:
4717 case XML_NOTATION_NODE:
4718 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004719 strcat(buf, "???");
4720 if (cur->next != NULL)
4721 strcat(buf, " ");
4722 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004723 case XML_ENTITY_NODE:
4724 case XML_PI_NODE:
4725 case XML_DTD_NODE:
4726 case XML_COMMENT_NODE:
4727 case XML_ELEMENT_DECL:
4728 case XML_ATTRIBUTE_DECL:
4729 case XML_ENTITY_DECL:
4730 case XML_XINCLUDE_START:
4731 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004732 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004733 }
4734 cur = cur->next;
4735 }
4736 if (glob) strcat(buf, ")");
4737}
4738
4739/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004740 * xmlValidateElementContent:
4741 * @ctxt: the validation context
4742 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004743 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004744 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004745 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004746 *
4747 * Try to validate the content model of an element
4748 *
4749 * returns 1 if valid or 0 if not and -1 in case of error
4750 */
4751
4752static int
4753xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004754 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004755 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00004756#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00004757 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00004758#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00004759 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004760 xmlElementContentPtr cont;
4761 const xmlChar *name;
4762
4763 if (elemDecl == NULL)
4764 return(-1);
4765 cont = elemDecl->content;
4766 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004767
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004768#ifdef LIBXML_REGEXP_ENABLED
4769 /* Build the regexp associated to the content model */
4770 if (elemDecl->contModel == NULL)
4771 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4772 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004773 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004774 } else {
4775 xmlRegExecCtxtPtr exec;
4776
Daniel Veillardec498e12003-02-05 11:01:50 +00004777 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
4778 return(-1);
4779 }
Daniel Veillard01992e02002-10-09 10:20:30 +00004780 ctxt->nodeMax = 0;
4781 ctxt->nodeNr = 0;
4782 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004783 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4784 if (exec != NULL) {
4785 cur = child;
4786 while (cur != NULL) {
4787 switch (cur->type) {
4788 case XML_ENTITY_REF_NODE:
4789 /*
4790 * Push the current node to be able to roll back
4791 * and process within the entity
4792 */
4793 if ((cur->children != NULL) &&
4794 (cur->children->children != NULL)) {
4795 nodeVPush(ctxt, cur);
4796 cur = cur->children->children;
4797 continue;
4798 }
4799 break;
4800 case XML_TEXT_NODE:
4801 if (xmlIsBlankNode(cur))
4802 break;
4803 ret = 0;
4804 goto fail;
4805 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00004806 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004807 ret = 0;
4808 goto fail;
4809 case XML_ELEMENT_NODE:
4810 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004811 xmlChar fn[50];
4812 xmlChar *fullname;
4813
4814 fullname = xmlBuildQName(cur->name,
4815 cur->ns->prefix, fn, 50);
4816 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004817 ret = -1;
4818 goto fail;
4819 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004820 ret = xmlRegExecPushString(exec, fullname, NULL);
4821 if ((fullname != fn) && (fullname != cur->name))
4822 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004823 } else {
4824 ret = xmlRegExecPushString(exec, cur->name, NULL);
4825 }
4826 break;
4827 default:
4828 break;
4829 }
4830 /*
4831 * Switch to next element
4832 */
4833 cur = cur->next;
4834 while (cur == NULL) {
4835 cur = nodeVPop(ctxt);
4836 if (cur == NULL)
4837 break;
4838 cur = cur->next;
4839 }
4840 }
4841 ret = xmlRegExecPushString(exec, NULL, NULL);
4842fail:
4843 xmlRegFreeExecCtxt(exec);
4844 }
4845 }
4846#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004847 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004848 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004849 */
4850 ctxt->vstateMax = 8;
4851 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
4852 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
4853 if (ctxt->vstateTab == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00004854 xmlErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004855 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004856 }
4857 /*
4858 * The first entry in the stack is reserved to the current state
4859 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00004860 ctxt->nodeMax = 0;
4861 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00004862 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004863 ctxt->vstate = &ctxt->vstateTab[0];
4864 ctxt->vstateNr = 1;
4865 CONT = cont;
4866 NODE = child;
4867 DEPTH = 0;
4868 OCCURS = 0;
4869 STATE = 0;
4870 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004871 if ((ret == -3) && (warn)) {
4872 VWARNING(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004873 "Content model for Element %s is ambiguous\n", name);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004874 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004875 /*
4876 * An entities reference appeared at this level.
4877 * Buid a minimal representation of this node content
4878 * sufficient to run the validation process on it
4879 */
4880 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004881 cur = child;
4882 while (cur != NULL) {
4883 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004884 case XML_ENTITY_REF_NODE:
4885 /*
4886 * Push the current node to be able to roll back
4887 * and process within the entity
4888 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004889 if ((cur->children != NULL) &&
4890 (cur->children->children != NULL)) {
4891 nodeVPush(ctxt, cur);
4892 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004893 continue;
4894 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00004895 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004896 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004897 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004898 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00004899 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004900 case XML_CDATA_SECTION_NODE:
4901 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004902 case XML_ELEMENT_NODE:
4903 /*
4904 * Allocate a new node and minimally fills in
4905 * what's required
4906 */
4907 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4908 if (tmp == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00004909 xmlErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004910 xmlFreeNodeList(repl);
4911 ret = -1;
4912 goto done;
4913 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004914 tmp->type = cur->type;
4915 tmp->name = cur->name;
4916 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004917 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00004918 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004919 if (repl == NULL)
4920 repl = last = tmp;
4921 else {
4922 last->next = tmp;
4923 last = tmp;
4924 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004925 if (cur->type == XML_CDATA_SECTION_NODE) {
4926 /*
4927 * E59 spaces in CDATA does not match the
4928 * nonterminal S
4929 */
4930 tmp->content = xmlStrdup(BAD_CAST "CDATA");
4931 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004932 break;
4933 default:
4934 break;
4935 }
4936 /*
4937 * Switch to next element
4938 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004939 cur = cur->next;
4940 while (cur == NULL) {
4941 cur = nodeVPop(ctxt);
4942 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004943 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004944 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004945 }
4946 }
4947
4948 /*
4949 * Relaunch the validation
4950 */
4951 ctxt->vstate = &ctxt->vstateTab[0];
4952 ctxt->vstateNr = 1;
4953 CONT = cont;
4954 NODE = repl;
4955 DEPTH = 0;
4956 OCCURS = 0;
4957 STATE = 0;
4958 ret = xmlValidateElementType(ctxt);
4959 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004960#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004961 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004962 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
4963 char expr[5000];
4964 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004965
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004966 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004967 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004968 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00004969#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004970 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004971 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004972 else
Daniel Veillard01992e02002-10-09 10:20:30 +00004973#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004974 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004975
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004976 if (name != NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004977 if (parent != NULL) VECTXT(ctxt, parent);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004978 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004979 "Element %s content does not follow the DTD\nExpecting %s, got %s\n",
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004980 name, expr, list);
4981 } else {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004982 if (parent != NULL) VECTXT(ctxt, parent);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004983 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004984 "Element content does not follow the DTD\nExpecting %s, got %s\n",
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004985 expr, list);
4986 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004987 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004988 if (name != NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004989 if (parent != NULL) VECTXT(ctxt, parent);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004990 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004991 "Element %s content does not follow the DTD\n",
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004992 name);
4993 } else {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004994 if (parent != NULL) VECTXT(ctxt, parent);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004995 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004996 "Element content does not follow the DTD\n");
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004997 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004998 }
4999 ret = 0;
5000 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005001 if (ret == -3)
5002 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005003
Daniel Veillard23e73572002-09-19 19:56:43 +00005004#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005005done:
5006 /*
5007 * Deallocate the copy if done, and free up the validation stack
5008 */
5009 while (repl != NULL) {
5010 tmp = repl->next;
5011 xmlFree(repl);
5012 repl = tmp;
5013 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005014 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005015 if (ctxt->vstateTab != NULL) {
5016 xmlFree(ctxt->vstateTab);
5017 ctxt->vstateTab = NULL;
5018 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005019#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005020 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005021 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005022 if (ctxt->nodeTab != NULL) {
5023 xmlFree(ctxt->nodeTab);
5024 ctxt->nodeTab = NULL;
5025 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005026 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005027
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005028}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005029
Owen Taylor3473f882001-02-23 17:55:21 +00005030/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005031 * xmlValidateCdataElement:
5032 * @ctxt: the validation context
5033 * @doc: a document instance
5034 * @elem: an element instance
5035 *
5036 * Check that an element follows #CDATA
5037 *
5038 * returns 1 if valid or 0 otherwise
5039 */
5040static int
5041xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5042 xmlNodePtr elem) {
5043 int ret = 1;
5044 xmlNodePtr cur, child;
5045
Daniel Veillardceb09b92002-10-04 11:46:37 +00005046 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005047 return(0);
5048
5049 child = elem->children;
5050
5051 cur = child;
5052 while (cur != NULL) {
5053 switch (cur->type) {
5054 case XML_ENTITY_REF_NODE:
5055 /*
5056 * Push the current node to be able to roll back
5057 * and process within the entity
5058 */
5059 if ((cur->children != NULL) &&
5060 (cur->children->children != NULL)) {
5061 nodeVPush(ctxt, cur);
5062 cur = cur->children->children;
5063 continue;
5064 }
5065 break;
5066 case XML_COMMENT_NODE:
5067 case XML_PI_NODE:
5068 case XML_TEXT_NODE:
5069 case XML_CDATA_SECTION_NODE:
5070 break;
5071 default:
5072 ret = 0;
5073 goto done;
5074 }
5075 /*
5076 * Switch to next element
5077 */
5078 cur = cur->next;
5079 while (cur == NULL) {
5080 cur = nodeVPop(ctxt);
5081 if (cur == NULL)
5082 break;
5083 cur = cur->next;
5084 }
5085 }
5086done:
5087 ctxt->nodeMax = 0;
5088 ctxt->nodeNr = 0;
5089 if (ctxt->nodeTab != NULL) {
5090 xmlFree(ctxt->nodeTab);
5091 ctxt->nodeTab = NULL;
5092 }
5093 return(ret);
5094}
5095
5096/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005097 * xmlValidateCheckMixed:
5098 * @ctxt: the validation context
5099 * @cont: the mixed content model
5100 * @qname: the qualified name as appearing in the serialization
5101 *
5102 * Check if the given node is part of the content model.
5103 *
5104 * Returns 1 if yes, 0 if no, -1 in case of error
5105 */
5106static int
5107xmlValidateCheckMixed(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
5108 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005109 const xmlChar *name;
5110 int plen;
5111 name = xmlSplitQName3(qname, &plen);
5112
5113 if (name == NULL) {
5114 while (cont != NULL) {
5115 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5116 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5117 return(1);
5118 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5119 (cont->c1 != NULL) &&
5120 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5121 if ((cont->c1->prefix == NULL) &&
5122 (xmlStrEqual(cont->c1->name, qname)))
5123 return(1);
5124 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5125 (cont->c1 == NULL) ||
5126 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005127 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5128 "Internal: MIXED struct corrupted\n",
5129 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005130 break;
5131 }
5132 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005133 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005134 } else {
5135 while (cont != NULL) {
5136 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5137 if ((cont->prefix != NULL) &&
5138 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5139 (xmlStrEqual(cont->name, name)))
5140 return(1);
5141 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5142 (cont->c1 != NULL) &&
5143 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5144 if ((cont->c1->prefix != NULL) &&
5145 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5146 (xmlStrEqual(cont->c1->name, name)))
5147 return(1);
5148 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5149 (cont->c1 == NULL) ||
5150 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005151 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5152 "Internal: MIXED struct corrupted\n",
5153 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005154 break;
5155 }
5156 cont = cont->c2;
5157 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005158 }
5159 return(0);
5160}
5161
5162/**
5163 * xmlValidGetElemDecl:
5164 * @ctxt: the validation context
5165 * @doc: a document instance
5166 * @elem: an element instance
5167 * @extsubset: pointer, (out) indicate if the declaration was found
5168 * in the external subset.
5169 *
5170 * Finds a declaration associated to an element in the document.
5171 *
5172 * returns the pointer to the declaration or NULL if not found.
5173 */
5174static xmlElementPtr
5175xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5176 xmlNodePtr elem, int *extsubset) {
5177 xmlElementPtr elemDecl = NULL;
5178 const xmlChar *prefix = NULL;
5179
5180 if ((elem == NULL) || (elem->name == NULL)) return(NULL);
5181 if (extsubset != NULL)
5182 *extsubset = 0;
5183
5184 /*
5185 * Fetch the declaration for the qualified name
5186 */
5187 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5188 prefix = elem->ns->prefix;
5189
5190 if (prefix != NULL) {
5191 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5192 elem->name, prefix);
5193 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5194 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5195 elem->name, prefix);
5196 if ((elemDecl != NULL) && (extsubset != NULL))
5197 *extsubset = 1;
5198 }
5199 }
5200
5201 /*
5202 * Fetch the declaration for the non qualified name
5203 * This is "non-strict" validation should be done on the
5204 * full QName but in that case being flexible makes sense.
5205 */
5206 if (elemDecl == NULL) {
5207 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5208 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5209 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5210 if ((elemDecl != NULL) && (extsubset != NULL))
5211 *extsubset = 1;
5212 }
5213 }
5214 if (elemDecl == NULL) {
5215 VECTXT(ctxt, elem);
5216 VERROR(ctxt->userData, "No declaration for element %s\n",
5217 elem->name);
5218 }
5219 return(elemDecl);
5220}
5221
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005222#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005223/**
5224 * xmlValidatePushElement:
5225 * @ctxt: the validation context
5226 * @doc: a document instance
5227 * @elem: an element instance
5228 * @qname: the qualified name as appearing in the serialization
5229 *
5230 * Push a new element start on the validation stack.
5231 *
5232 * returns 1 if no validation problem was found or 0 otherwise
5233 */
5234int
5235xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5236 xmlNodePtr elem, const xmlChar *qname) {
5237 int ret = 1;
5238 xmlElementPtr eDecl;
5239 int extsubset = 0;
5240
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005241/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005242 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5243 xmlValidStatePtr state = ctxt->vstate;
5244 xmlElementPtr elemDecl;
5245
5246 /*
5247 * Check the new element agaisnt the content model of the new elem.
5248 */
5249 if (state->elemDecl != NULL) {
5250 elemDecl = state->elemDecl;
5251
5252 switch(elemDecl->etype) {
5253 case XML_ELEMENT_TYPE_UNDEFINED:
5254 ret = 0;
5255 break;
5256 case XML_ELEMENT_TYPE_EMPTY:
5257 VECTXT(ctxt, state->node);
5258 VERROR(ctxt->userData,
5259 "Element %s was declared EMPTY this one has content\n",
5260 state->node->name);
5261 ret = 0;
5262 break;
5263 case XML_ELEMENT_TYPE_ANY:
5264 /* I don't think anything is required then */
5265 break;
5266 case XML_ELEMENT_TYPE_MIXED:
5267 /* simple case of declared as #PCDATA */
5268 if ((elemDecl->content != NULL) &&
5269 (elemDecl->content->type ==
5270 XML_ELEMENT_CONTENT_PCDATA)) {
5271 VECTXT(ctxt, state->node);
5272 VERROR(ctxt->userData,
5273 "Element %s was declared #PCDATA but contains non text nodes\n",
5274 state->node->name);
5275 ret = 0;
5276 } else {
5277 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5278 qname);
5279 if (ret != 1) {
5280 VECTXT(ctxt, state->node);
5281 VERROR(ctxt->userData,
5282 "Element %s is not declared in %s list of possible children\n",
5283 qname, state->node->name);
5284 }
5285 }
5286 break;
5287 case XML_ELEMENT_TYPE_ELEMENT:
5288 /*
5289 * TODO:
5290 * VC: Standalone Document Declaration
5291 * - element types with element content, if white space
5292 * occurs directly within any instance of those types.
5293 */
5294 if (state->exec != NULL) {
5295 ret = xmlRegExecPushString(state->exec, qname, NULL);
5296 if (ret < 0) {
5297 VECTXT(ctxt, state->node);
5298 VERROR(ctxt->userData,
5299 "Element %s content does not follow the DTD\nMisplaced %s\n",
5300 state->node->name, qname);
5301 ret = 0;
5302 } else {
5303 ret = 1;
5304 }
5305 }
5306 break;
5307 }
5308 }
5309 }
5310 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5311 vstateVPush(ctxt, eDecl, elem);
5312 return(ret);
5313}
5314
5315/**
5316 * xmlValidatePushCData:
5317 * @ctxt: the validation context
5318 * @data: some character data read
5319 * @len: the lenght of the data
5320 *
5321 * check the CData parsed for validation in the current stack
5322 *
5323 * returns 1 if no validation problem was found or 0 otherwise
5324 */
5325int
5326xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5327 int ret = 1;
5328
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005329/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005330 if (len <= 0)
5331 return(ret);
5332 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5333 xmlValidStatePtr state = ctxt->vstate;
5334 xmlElementPtr elemDecl;
5335
5336 /*
5337 * Check the new element agaisnt the content model of the new elem.
5338 */
5339 if (state->elemDecl != NULL) {
5340 elemDecl = state->elemDecl;
5341
5342 switch(elemDecl->etype) {
5343 case XML_ELEMENT_TYPE_UNDEFINED:
5344 ret = 0;
5345 break;
5346 case XML_ELEMENT_TYPE_EMPTY:
5347 VECTXT(ctxt, state->node);
5348 VERROR(ctxt->userData,
5349 "Element %s was declared EMPTY this one has content\n",
5350 state->node->name);
5351 ret = 0;
5352 break;
5353 case XML_ELEMENT_TYPE_ANY:
5354 break;
5355 case XML_ELEMENT_TYPE_MIXED:
5356 break;
5357 case XML_ELEMENT_TYPE_ELEMENT:
5358 if (len > 0) {
5359 int i;
5360
5361 for (i = 0;i < len;i++) {
5362 if (!IS_BLANK(data[i])) {
5363 VECTXT(ctxt, state->node);
5364 VERROR(ctxt->userData,
5365 "Element %s content does not follow the DTD\nText not allowed\n",
5366 state->node->name);
5367 ret = 0;
5368 goto done;
5369 }
5370 }
5371 /*
5372 * TODO:
5373 * VC: Standalone Document Declaration
5374 * element types with element content, if white space
5375 * occurs directly within any instance of those types.
5376 */
5377 }
5378 break;
5379 }
5380 }
5381 }
5382done:
5383 return(ret);
5384}
5385
5386/**
5387 * xmlValidatePopElement:
5388 * @ctxt: the validation context
5389 * @doc: a document instance
5390 * @elem: an element instance
5391 * @qname: the qualified name as appearing in the serialization
5392 *
5393 * Pop the element end from the validation stack.
5394 *
5395 * returns 1 if no validation problem was found or 0 otherwise
5396 */
5397int
5398xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005399 xmlNodePtr elem ATTRIBUTE_UNUSED,
5400 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005401 int ret = 1;
5402
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005403/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005404 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5405 xmlValidStatePtr state = ctxt->vstate;
5406 xmlElementPtr elemDecl;
5407
5408 /*
5409 * Check the new element agaisnt the content model of the new elem.
5410 */
5411 if (state->elemDecl != NULL) {
5412 elemDecl = state->elemDecl;
5413
5414 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5415 if (state->exec != NULL) {
5416 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5417 if (ret == 0) {
5418 VECTXT(ctxt, state->node);
5419 VERROR(ctxt->userData,
5420 "Element %s content does not follow the DTD\nExpecting more child\n",
5421 state->node->name);
5422 } else {
5423 /*
5424 * previous validation errors should not generate
5425 * a new one here
5426 */
5427 ret = 1;
5428 }
5429 }
5430 }
5431 }
5432 vstateVPop(ctxt);
5433 }
5434 return(ret);
5435}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005436#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005437
5438/**
Owen Taylor3473f882001-02-23 17:55:21 +00005439 * xmlValidateOneElement:
5440 * @ctxt: the validation context
5441 * @doc: a document instance
5442 * @elem: an element instance
5443 *
5444 * Try to validate a single element and it's attributes,
5445 * basically it does the following checks as described by the
5446 * XML-1.0 recommendation:
5447 * - [ VC: Element Valid ]
5448 * - [ VC: Required Attribute ]
5449 * Then call xmlValidateOneAttribute() for each attribute present.
5450 *
5451 * The ID/IDREF checkings are done separately
5452 *
5453 * returns 1 if valid or 0 otherwise
5454 */
5455
5456int
5457xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5458 xmlNodePtr elem) {
5459 xmlElementPtr elemDecl = NULL;
5460 xmlElementContentPtr cont;
5461 xmlAttributePtr attr;
5462 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005463 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005464 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005465 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005466
5467 CHECK_DTD;
5468
5469 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005470 switch (elem->type) {
5471 case XML_ATTRIBUTE_NODE:
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005472 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005473 VERROR(ctxt->userData,
5474 "Attribute element not expected here\n");
5475 return(0);
5476 case XML_TEXT_NODE:
5477 if (elem->children != NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005478 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005479 VERROR(ctxt->userData, "Text element has childs !\n");
5480 return(0);
5481 }
5482 if (elem->properties != NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005483 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005484 VERROR(ctxt->userData, "Text element has attributes !\n");
5485 return(0);
5486 }
5487 if (elem->ns != NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005488 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005489 VERROR(ctxt->userData, "Text element has namespace !\n");
5490 return(0);
5491 }
5492 if (elem->nsDef != NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005493 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005494 VERROR(ctxt->userData,
5495 "Text element carries namespace definitions !\n");
5496 return(0);
5497 }
5498 if (elem->content == NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005499 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005500 VERROR(ctxt->userData,
5501 "Text element has no content !\n");
5502 return(0);
5503 }
5504 return(1);
5505 case XML_XINCLUDE_START:
5506 case XML_XINCLUDE_END:
5507 return(1);
5508 case XML_CDATA_SECTION_NODE:
5509 case XML_ENTITY_REF_NODE:
5510 case XML_PI_NODE:
5511 case XML_COMMENT_NODE:
5512 return(1);
5513 case XML_ENTITY_NODE:
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005514 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005515 VERROR(ctxt->userData,
5516 "Entity element not expected here\n");
5517 return(0);
5518 case XML_NOTATION_NODE:
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005519 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005520 VERROR(ctxt->userData,
5521 "Notation element not expected here\n");
5522 return(0);
5523 case XML_DOCUMENT_NODE:
5524 case XML_DOCUMENT_TYPE_NODE:
5525 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005526 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005527 VERROR(ctxt->userData,
5528 "Document element not expected here\n");
5529 return(0);
5530 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005531 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005532 VERROR(ctxt->userData,
5533 "\n");
5534 return(0);
5535 case XML_ELEMENT_NODE:
5536 break;
5537 default:
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005538 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005539 VERROR(ctxt->userData,
5540 "unknown element type %d\n", elem->type);
5541 return(0);
5542 }
Owen Taylor3473f882001-02-23 17:55:21 +00005543
5544 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005545 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005546 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005547 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5548 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005549 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005550
Daniel Veillardea7751d2002-12-20 00:16:24 +00005551 /*
5552 * If vstateNr is not zero that means continuous validation is
5553 * activated, do not try to check the content model at that level.
5554 */
5555 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005556 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005557 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005558 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005559 VECTXT(ctxt, elem);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005560 VERROR(ctxt->userData, "No declaration for element %s\n",
5561 elem->name);
5562 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005563 case XML_ELEMENT_TYPE_EMPTY:
5564 if (elem->children != NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005565 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005566 VERROR(ctxt->userData,
5567 "Element %s was declared EMPTY this one has content\n",
5568 elem->name);
5569 ret = 0;
5570 }
5571 break;
5572 case XML_ELEMENT_TYPE_ANY:
5573 /* I don't think anything is required then */
5574 break;
5575 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005576
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005577 /* simple case of declared as #PCDATA */
5578 if ((elemDecl->content != NULL) &&
5579 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5580 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5581 if (!ret) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005582 VECTXT(ctxt, elem);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005583 VERROR(ctxt->userData,
5584 "Element %s was declared #PCDATA but contains non text nodes\n",
5585 elem->name);
5586 }
5587 break;
5588 }
Owen Taylor3473f882001-02-23 17:55:21 +00005589 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005590 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005591 while (child != NULL) {
5592 if (child->type == XML_ELEMENT_NODE) {
5593 name = child->name;
5594 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005595 xmlChar fn[50];
5596 xmlChar *fullname;
5597
5598 fullname = xmlBuildQName(child->name, child->ns->prefix,
5599 fn, 50);
5600 if (fullname == NULL)
5601 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005602 cont = elemDecl->content;
5603 while (cont != NULL) {
5604 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005605 if (xmlStrEqual(cont->name, fullname))
5606 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005607 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5608 (cont->c1 != NULL) &&
5609 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005610 if (xmlStrEqual(cont->c1->name, fullname))
5611 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005612 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5613 (cont->c1 == NULL) ||
5614 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005615 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5616 "Internal: MIXED struct corrupted\n",
5617 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005618 break;
5619 }
5620 cont = cont->c2;
5621 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005622 if ((fullname != fn) && (fullname != child->name))
5623 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005624 if (cont != NULL)
5625 goto child_ok;
5626 }
5627 cont = elemDecl->content;
5628 while (cont != NULL) {
5629 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5630 if (xmlStrEqual(cont->name, name)) break;
5631 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5632 (cont->c1 != NULL) &&
5633 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5634 if (xmlStrEqual(cont->c1->name, name)) break;
5635 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5636 (cont->c1 == NULL) ||
5637 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005638 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5639 "Internal: MIXED struct corrupted\n",
5640 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005641 break;
5642 }
5643 cont = cont->c2;
5644 }
5645 if (cont == NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005646 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005647 VERROR(ctxt->userData,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00005648 "Element %s is not declared in %s list of possible children\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005649 name, elem->name);
5650 ret = 0;
5651 }
5652 }
5653child_ok:
5654 child = child->next;
5655 }
5656 break;
5657 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005658 if ((doc->standalone == 1) && (extsubset == 1)) {
5659 /*
5660 * VC: Standalone Document Declaration
5661 * - element types with element content, if white space
5662 * occurs directly within any instance of those types.
5663 */
5664 child = elem->children;
5665 while (child != NULL) {
5666 if (child->type == XML_TEXT_NODE) {
5667 const xmlChar *content = child->content;
5668
5669 while (IS_BLANK(*content))
5670 content++;
5671 if (*content == 0) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005672 VECTXT(ctxt, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005673 VERROR(ctxt->userData,
5674"standalone: %s declared in the external subset contains white spaces nodes\n",
5675 elem->name);
5676 ret = 0;
5677 break;
5678 }
5679 }
5680 child =child->next;
5681 }
5682 }
Owen Taylor3473f882001-02-23 17:55:21 +00005683 child = elem->children;
5684 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005685 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005686 if (tmp <= 0)
5687 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005688 break;
5689 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005690 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00005691
5692 /* [ VC: Required Attribute ] */
5693 attr = elemDecl->attributes;
5694 while (attr != NULL) {
5695 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005696 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005697
Daniel Veillarde4301c82002-02-13 13:32:35 +00005698 if ((attr->prefix == NULL) &&
5699 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5700 xmlNsPtr ns;
5701
5702 ns = elem->nsDef;
5703 while (ns != NULL) {
5704 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005705 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005706 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00005707 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005708 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5709 xmlNsPtr ns;
5710
5711 ns = elem->nsDef;
5712 while (ns != NULL) {
5713 if (xmlStrEqual(attr->name, ns->prefix))
5714 goto found;
5715 ns = ns->next;
5716 }
5717 } else {
5718 xmlAttrPtr attrib;
5719
5720 attrib = elem->properties;
5721 while (attrib != NULL) {
5722 if (xmlStrEqual(attrib->name, attr->name)) {
5723 if (attr->prefix != NULL) {
5724 xmlNsPtr nameSpace = attrib->ns;
5725
5726 if (nameSpace == NULL)
5727 nameSpace = elem->ns;
5728 /*
5729 * qualified names handling is problematic, having a
5730 * different prefix should be possible but DTDs don't
5731 * allow to define the URI instead of the prefix :-(
5732 */
5733 if (nameSpace == NULL) {
5734 if (qualified < 0)
5735 qualified = 0;
5736 } else if (!xmlStrEqual(nameSpace->prefix,
5737 attr->prefix)) {
5738 if (qualified < 1)
5739 qualified = 1;
5740 } else
5741 goto found;
5742 } else {
5743 /*
5744 * We should allow applications to define namespaces
5745 * for their application even if the DTD doesn't
5746 * carry one, otherwise, basically we would always
5747 * break.
5748 */
5749 goto found;
5750 }
5751 }
5752 attrib = attrib->next;
5753 }
Owen Taylor3473f882001-02-23 17:55:21 +00005754 }
5755 if (qualified == -1) {
5756 if (attr->prefix == NULL) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005757 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005758 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005759 "Element %s does not carry attribute %s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005760 elem->name, attr->name);
5761 ret = 0;
5762 } else {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005763 VECTXT(ctxt, elem);
Owen Taylor3473f882001-02-23 17:55:21 +00005764 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005765 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005766 elem->name, attr->prefix,attr->name);
5767 ret = 0;
5768 }
5769 } else if (qualified == 0) {
5770 VWARNING(ctxt->userData,
5771 "Element %s required attribute %s:%s has no prefix\n",
5772 elem->name, attr->prefix,attr->name);
5773 } else if (qualified == 1) {
5774 VWARNING(ctxt->userData,
5775 "Element %s required attribute %s:%s has different prefix\n",
5776 elem->name, attr->prefix,attr->name);
5777 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005778 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5779 /*
5780 * Special tests checking #FIXED namespace declarations
5781 * have the right value since this is not done as an
5782 * attribute checking
5783 */
5784 if ((attr->prefix == NULL) &&
5785 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5786 xmlNsPtr ns;
5787
5788 ns = elem->nsDef;
5789 while (ns != NULL) {
5790 if (ns->prefix == NULL) {
5791 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005792 VECTXT(ctxt, elem);
Daniel Veillarde4301c82002-02-13 13:32:35 +00005793 VERROR(ctxt->userData,
5794 "Element %s namespace name for default namespace does not match the DTD\n",
5795 elem->name);
Daniel Veillardc7612992002-02-17 22:47:37 +00005796 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005797 }
5798 goto found;
5799 }
5800 ns = ns->next;
5801 }
5802 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5803 xmlNsPtr ns;
5804
5805 ns = elem->nsDef;
5806 while (ns != NULL) {
5807 if (xmlStrEqual(attr->name, ns->prefix)) {
5808 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005809 VECTXT(ctxt, elem);
Daniel Veillarde4301c82002-02-13 13:32:35 +00005810 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005811 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillarde4301c82002-02-13 13:32:35 +00005812 elem->name, ns->prefix);
Daniel Veillardc7612992002-02-17 22:47:37 +00005813 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005814 }
5815 goto found;
5816 }
5817 ns = ns->next;
5818 }
5819 }
Owen Taylor3473f882001-02-23 17:55:21 +00005820 }
5821found:
5822 attr = attr->nexth;
5823 }
5824 return(ret);
5825}
5826
5827/**
5828 * xmlValidateRoot:
5829 * @ctxt: the validation context
5830 * @doc: a document instance
5831 *
5832 * Try to validate a the root element
5833 * basically it does the following check as described by the
5834 * XML-1.0 recommendation:
5835 * - [ VC: Root Element Type ]
5836 * it doesn't try to recurse or apply other check to the element
5837 *
5838 * returns 1 if valid or 0 otherwise
5839 */
5840
5841int
5842xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
5843 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00005844 int ret;
5845
Owen Taylor3473f882001-02-23 17:55:21 +00005846 if (doc == NULL) return(0);
5847
5848 root = xmlDocGetRootElement(doc);
5849 if ((root == NULL) || (root->name == NULL)) {
5850 VERROR(ctxt->userData, "Not valid: no root element\n");
5851 return(0);
5852 }
5853
5854 /*
5855 * When doing post validation against a separate DTD, those may
5856 * no internal subset has been generated
5857 */
5858 if ((doc->intSubset != NULL) &&
5859 (doc->intSubset->name != NULL)) {
5860 /*
5861 * Check first the document root against the NQName
5862 */
5863 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
5864 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005865 xmlChar fn[50];
5866 xmlChar *fullname;
5867
5868 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
5869 if (fullname == NULL) {
5870 VERROR(ctxt->userData, "Out of memory\n");
5871 return(0);
5872 }
5873 ret = xmlStrEqual(doc->intSubset->name, fullname);
5874 if ((fullname != fn) && (fullname != root->name))
5875 xmlFree(fullname);
5876 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00005877 goto name_ok;
5878 }
5879 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
5880 (xmlStrEqual(root->name, BAD_CAST "html")))
5881 goto name_ok;
Daniel Veillard76575762002-09-05 14:21:15 +00005882 VECTXT(ctxt, root);
Owen Taylor3473f882001-02-23 17:55:21 +00005883 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005884 "Not valid: root and DTD name do not match '%s' and '%s'\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005885 root->name, doc->intSubset->name);
5886 return(0);
5887
5888 }
5889 }
5890name_ok:
5891 return(1);
5892}
5893
5894
5895/**
5896 * xmlValidateElement:
5897 * @ctxt: the validation context
5898 * @doc: a document instance
5899 * @elem: an element instance
5900 *
5901 * Try to validate the subtree under an element
5902 *
5903 * returns 1 if valid or 0 otherwise
5904 */
5905
5906int
5907xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
5908 xmlNodePtr child;
5909 xmlAttrPtr attr;
5910 xmlChar *value;
5911 int ret = 1;
5912
5913 if (elem == NULL) return(0);
5914
5915 /*
5916 * XInclude elements were added after parsing in the infoset,
5917 * they don't really mean anything validation wise.
5918 */
5919 if ((elem->type == XML_XINCLUDE_START) ||
5920 (elem->type == XML_XINCLUDE_END))
5921 return(1);
5922
5923 CHECK_DTD;
5924
Daniel Veillard10ea86c2001-06-20 13:55:33 +00005925 /*
5926 * Entities references have to be handled separately
5927 */
5928 if (elem->type == XML_ENTITY_REF_NODE) {
5929 return(1);
5930 }
5931
Owen Taylor3473f882001-02-23 17:55:21 +00005932 ret &= xmlValidateOneElement(ctxt, doc, elem);
5933 attr = elem->properties;
5934 while(attr != NULL) {
5935 value = xmlNodeListGetString(doc, attr->children, 0);
5936 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
5937 if (value != NULL)
5938 xmlFree(value);
5939 attr= attr->next;
5940 }
5941 child = elem->children;
5942 while (child != NULL) {
5943 ret &= xmlValidateElement(ctxt, doc, child);
5944 child = child->next;
5945 }
5946
5947 return(ret);
5948}
5949
Daniel Veillard8730c562001-02-26 10:49:57 +00005950/**
5951 * xmlValidateRef:
5952 * @ref: A reference to be validated
5953 * @ctxt: Validation context
5954 * @name: Name of ID we are searching for
5955 *
5956 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005957static void
Daniel Veillard8730c562001-02-26 10:49:57 +00005958xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00005959 const xmlChar *name) {
5960 xmlAttrPtr id;
5961 xmlAttrPtr attr;
5962
5963 if (ref == NULL)
5964 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005965 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00005966 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005967 attr = ref->attr;
5968 if (attr == NULL) {
5969 xmlChar *dup, *str = NULL, *cur, save;
5970
5971 dup = xmlStrdup(name);
5972 if (dup == NULL) {
5973 ctxt->valid = 0;
5974 return;
5975 }
5976 cur = dup;
5977 while (*cur != 0) {
5978 str = cur;
5979 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
5980 save = *cur;
5981 *cur = 0;
5982 id = xmlGetID(ctxt->doc, str);
5983 if (id == NULL) {
5984 VERROR(ctxt->userData,
5985 "attribute %s line %d references an unknown ID \"%s\"\n",
5986 ref->name, ref->lineno, str);
5987 ctxt->valid = 0;
5988 }
5989 if (save == 0)
5990 break;
5991 *cur = save;
5992 while (IS_BLANK(*cur)) cur++;
5993 }
5994 xmlFree(dup);
5995 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00005996 id = xmlGetID(ctxt->doc, name);
5997 if (id == NULL) {
Daniel Veillard76575762002-09-05 14:21:15 +00005998 VECTXT(ctxt, attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005999 VERROR(ctxt->userData,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006000 "IDREF attribute %s references an unknown ID \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00006001 attr->name, name);
6002 ctxt->valid = 0;
6003 }
6004 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6005 xmlChar *dup, *str = NULL, *cur, save;
6006
6007 dup = xmlStrdup(name);
6008 if (dup == NULL) {
6009 ctxt->valid = 0;
6010 return;
6011 }
6012 cur = dup;
6013 while (*cur != 0) {
6014 str = cur;
6015 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6016 save = *cur;
6017 *cur = 0;
6018 id = xmlGetID(ctxt->doc, str);
6019 if (id == NULL) {
Daniel Veillard76575762002-09-05 14:21:15 +00006020 VECTXT(ctxt, attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00006021 VERROR(ctxt->userData,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006022 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00006023 attr->name, str);
6024 ctxt->valid = 0;
6025 }
6026 if (save == 0)
6027 break;
6028 *cur = save;
6029 while (IS_BLANK(*cur)) cur++;
6030 }
6031 xmlFree(dup);
6032 }
6033}
6034
6035/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006036 * xmlWalkValidateList:
6037 * @data: Contents of current link
6038 * @user: Value supplied by the user
6039 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006040 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006041 */
6042static int
6043xmlWalkValidateList(const void *data, const void *user)
6044{
6045 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6046 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6047 return 1;
6048}
6049
6050/**
6051 * xmlValidateCheckRefCallback:
6052 * @ref_list: List of references
6053 * @ctxt: Validation context
6054 * @name: Name of ID we are searching for
6055 *
6056 */
6057static void
6058xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6059 const xmlChar *name) {
6060 xmlValidateMemo memo;
6061
6062 if (ref_list == NULL)
6063 return;
6064 memo.ctxt = ctxt;
6065 memo.name = name;
6066
6067 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6068
6069}
6070
6071/**
Owen Taylor3473f882001-02-23 17:55:21 +00006072 * xmlValidateDocumentFinal:
6073 * @ctxt: the validation context
6074 * @doc: a document instance
6075 *
6076 * Does the final step for the document validation once all the
6077 * incremental validation steps have been completed
6078 *
6079 * basically it does the following checks described by the XML Rec
6080 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006081 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006082 *
6083 * returns 1 if valid or 0 otherwise
6084 */
6085
6086int
6087xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6088 xmlRefTablePtr table;
6089
6090 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006091 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6092 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006093 return(0);
6094 }
6095
6096 /*
6097 * Check all the NOTATION/NOTATIONS attributes
6098 */
6099 /*
6100 * Check all the ENTITY/ENTITIES attributes definition for validity
6101 */
6102 /*
6103 * Check all the IDREF/IDREFS attributes definition for validity
6104 */
6105 table = (xmlRefTablePtr) doc->refs;
6106 ctxt->doc = doc;
6107 ctxt->valid = 1;
6108 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6109 return(ctxt->valid);
6110}
6111
6112/**
6113 * xmlValidateDtd:
6114 * @ctxt: the validation context
6115 * @doc: a document instance
6116 * @dtd: a dtd instance
6117 *
6118 * Try to validate the document against the dtd instance
6119 *
6120 * basically it does check all the definitions in the DtD.
6121 *
6122 * returns 1 if valid or 0 otherwise
6123 */
6124
6125int
6126xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6127 int ret;
6128 xmlDtdPtr oldExt;
6129 xmlNodePtr root;
6130
6131 if (dtd == NULL) return(0);
6132 if (doc == NULL) return(0);
6133 oldExt = doc->extSubset;
6134 doc->extSubset = dtd;
6135 ret = xmlValidateRoot(ctxt, doc);
6136 if (ret == 0) {
6137 doc->extSubset = oldExt;
6138 return(ret);
6139 }
6140 if (doc->ids != NULL) {
6141 xmlFreeIDTable(doc->ids);
6142 doc->ids = NULL;
6143 }
6144 if (doc->refs != NULL) {
6145 xmlFreeRefTable(doc->refs);
6146 doc->refs = NULL;
6147 }
6148 root = xmlDocGetRootElement(doc);
6149 ret = xmlValidateElement(ctxt, doc, root);
6150 ret &= xmlValidateDocumentFinal(ctxt, doc);
6151 doc->extSubset = oldExt;
6152 return(ret);
6153}
6154
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006155static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006156xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6157 const xmlChar *name ATTRIBUTE_UNUSED) {
6158 if (cur == NULL)
6159 return;
6160 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6161 xmlChar *notation = cur->content;
6162
Daniel Veillard878eab02002-02-19 13:46:09 +00006163 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006164 int ret;
6165
6166 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6167 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006168 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006169 }
6170 }
6171 }
6172}
6173
6174static void
Owen Taylor3473f882001-02-23 17:55:21 +00006175xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006176 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006177 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006178 xmlDocPtr doc;
6179 xmlElementPtr elem;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006180
Owen Taylor3473f882001-02-23 17:55:21 +00006181 if (cur == NULL)
6182 return;
6183 switch (cur->atype) {
6184 case XML_ATTRIBUTE_CDATA:
6185 case XML_ATTRIBUTE_ID:
6186 case XML_ATTRIBUTE_IDREF :
6187 case XML_ATTRIBUTE_IDREFS:
6188 case XML_ATTRIBUTE_NMTOKEN:
6189 case XML_ATTRIBUTE_NMTOKENS:
6190 case XML_ATTRIBUTE_ENUMERATION:
6191 break;
6192 case XML_ATTRIBUTE_ENTITY:
6193 case XML_ATTRIBUTE_ENTITIES:
6194 case XML_ATTRIBUTE_NOTATION:
6195 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006196
6197 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6198 cur->atype, cur->defaultValue);
6199 if ((ret == 0) && (ctxt->valid == 1))
6200 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006201 }
6202 if (cur->tree != NULL) {
6203 xmlEnumerationPtr tree = cur->tree;
6204 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006205 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006206 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006207 if ((ret == 0) && (ctxt->valid == 1))
6208 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006209 tree = tree->next;
6210 }
6211 }
6212 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006213 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6214 doc = cur->doc;
6215 if ((doc == NULL) || (cur->elem == NULL)) {
6216 VERROR(ctxt->userData,
6217 "xmlValidateAttributeCallback(%s): internal error\n",
6218 cur->name);
6219 return;
6220 }
6221 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6222 if (elem == NULL)
6223 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
6224 if (elem == NULL) {
6225 VERROR(ctxt->userData,
6226 "attribute %s: could not find decl for element %s\n",
6227 cur->name, cur->elem);
6228 return;
6229 }
6230 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
6231 VERROR(ctxt->userData,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006232 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillard878eab02002-02-19 13:46:09 +00006233 cur->name, cur->elem);
6234 ctxt->valid = 0;
6235 }
6236 }
Owen Taylor3473f882001-02-23 17:55:21 +00006237}
6238
6239/**
6240 * xmlValidateDtdFinal:
6241 * @ctxt: the validation context
6242 * @doc: a document instance
6243 *
6244 * Does the final step for the dtds validation once all the
6245 * subsets have been parsed
6246 *
6247 * basically it does the following checks described by the XML Rec
6248 * - check that ENTITY and ENTITIES type attributes default or
6249 * possible values matches one of the defined entities.
6250 * - check that NOTATION type attributes default or
6251 * possible values matches one of the defined notations.
6252 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006253 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006254 */
6255
6256int
6257xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006258 xmlDtdPtr dtd;
6259 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006260 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006261
6262 if (doc == NULL) return(0);
6263 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6264 return(0);
6265 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006266 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006267 dtd = doc->intSubset;
6268 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6269 table = (xmlAttributeTablePtr) dtd->attributes;
6270 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006271 }
6272 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006273 entities = (xmlEntitiesTablePtr) dtd->entities;
6274 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6275 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006276 }
6277 dtd = doc->extSubset;
6278 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6279 table = (xmlAttributeTablePtr) dtd->attributes;
6280 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006281 }
6282 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006283 entities = (xmlEntitiesTablePtr) dtd->entities;
6284 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6285 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006286 }
6287 return(ctxt->valid);
6288}
6289
6290/**
6291 * xmlValidateDocument:
6292 * @ctxt: the validation context
6293 * @doc: a document instance
6294 *
6295 * Try to validate the document instance
6296 *
6297 * basically it does the all the checks described by the XML Rec
6298 * i.e. validates the internal and external subset (if present)
6299 * and validate the document tree.
6300 *
6301 * returns 1 if valid or 0 otherwise
6302 */
6303
6304int
6305xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6306 int ret;
6307 xmlNodePtr root;
6308
Daniel Veillard2fd85422002-10-16 14:32:41 +00006309 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
6310 VERROR(ctxt->userData, "no DTD found!\n" );
Owen Taylor3473f882001-02-23 17:55:21 +00006311 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006312 }
Owen Taylor3473f882001-02-23 17:55:21 +00006313 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6314 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6315 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6316 doc->intSubset->SystemID);
6317 if (doc->extSubset == NULL) {
6318 if (doc->intSubset->SystemID != NULL) {
6319 VERROR(ctxt->userData,
6320 "Could not load the external subset \"%s\"\n",
6321 doc->intSubset->SystemID);
6322 } else {
6323 VERROR(ctxt->userData,
6324 "Could not load the external subset \"%s\"\n",
6325 doc->intSubset->ExternalID);
6326 }
6327 return(0);
6328 }
6329 }
6330
6331 if (doc->ids != NULL) {
6332 xmlFreeIDTable(doc->ids);
6333 doc->ids = NULL;
6334 }
6335 if (doc->refs != NULL) {
6336 xmlFreeRefTable(doc->refs);
6337 doc->refs = NULL;
6338 }
6339 ret = xmlValidateDtdFinal(ctxt, doc);
6340 if (!xmlValidateRoot(ctxt, doc)) return(0);
6341
6342 root = xmlDocGetRootElement(doc);
6343 ret &= xmlValidateElement(ctxt, doc, root);
6344 ret &= xmlValidateDocumentFinal(ctxt, doc);
6345 return(ret);
6346}
6347
Owen Taylor3473f882001-02-23 17:55:21 +00006348/************************************************************************
6349 * *
6350 * Routines for dynamic validation editing *
6351 * *
6352 ************************************************************************/
6353
6354/**
6355 * xmlValidGetPotentialChildren:
6356 * @ctree: an element content tree
6357 * @list: an array to store the list of child names
6358 * @len: a pointer to the number of element in the list
6359 * @max: the size of the array
6360 *
6361 * Build/extend a list of potential children allowed by the content tree
6362 *
6363 * returns the number of element in the list, or -1 in case of error.
6364 */
6365
6366int
6367xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6368 int *len, int max) {
6369 int i;
6370
6371 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6372 return(-1);
6373 if (*len >= max) return(*len);
6374
6375 switch (ctree->type) {
6376 case XML_ELEMENT_CONTENT_PCDATA:
6377 for (i = 0; i < *len;i++)
6378 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6379 list[(*len)++] = BAD_CAST "#PCDATA";
6380 break;
6381 case XML_ELEMENT_CONTENT_ELEMENT:
6382 for (i = 0; i < *len;i++)
6383 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6384 list[(*len)++] = ctree->name;
6385 break;
6386 case XML_ELEMENT_CONTENT_SEQ:
6387 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6388 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6389 break;
6390 case XML_ELEMENT_CONTENT_OR:
6391 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6392 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6393 break;
6394 }
6395
6396 return(*len);
6397}
6398
6399/**
6400 * xmlValidGetValidElements:
6401 * @prev: an element to insert after
6402 * @next: an element to insert next
6403 * @list: an array to store the list of child names
6404 * @max: the size of the array
6405 *
6406 * This function returns the list of authorized children to insert
6407 * within an existing tree while respecting the validity constraints
6408 * forced by the Dtd. The insertion point is defined using @prev and
6409 * @next in the following ways:
6410 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6411 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6412 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6413 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6414 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6415 *
6416 * pointers to the element names are inserted at the beginning of the array
6417 * and do not need to be freed.
6418 *
6419 * returns the number of element in the list, or -1 in case of error. If
6420 * the function returns the value @max the caller is invited to grow the
6421 * receiving array and retry.
6422 */
6423
6424int
6425xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
6426 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006427 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006428 int nb_valid_elements = 0;
6429 const xmlChar *elements[256];
6430 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006431 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006432
6433 xmlNode *ref_node;
6434 xmlNode *parent;
6435 xmlNode *test_node;
6436
6437 xmlNode *prev_next;
6438 xmlNode *next_prev;
6439 xmlNode *parent_childs;
6440 xmlNode *parent_last;
6441
6442 xmlElement *element_desc;
6443
Daniel Veillardbb4e46d2002-03-10 16:49:08 +00006444 memset(&vctxt, 0, sizeof (xmlValidCtxt));
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006445
Owen Taylor3473f882001-02-23 17:55:21 +00006446 if (prev == NULL && next == NULL)
6447 return(-1);
6448
6449 if (list == NULL) return(-1);
6450 if (max <= 0) return(-1);
6451
6452 nb_valid_elements = 0;
6453 ref_node = prev ? prev : next;
6454 parent = ref_node->parent;
6455
6456 /*
6457 * Retrieves the parent element declaration
6458 */
6459 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6460 parent->name);
6461 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6462 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6463 parent->name);
6464 if (element_desc == NULL) return(-1);
6465
6466 /*
6467 * Do a backup of the current tree structure
6468 */
6469 prev_next = prev ? prev->next : NULL;
6470 next_prev = next ? next->prev : NULL;
6471 parent_childs = parent->children;
6472 parent_last = parent->last;
6473
6474 /*
6475 * Creates a dummy node and insert it into the tree
6476 */
6477 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
6478 test_node->doc = ref_node->doc;
6479 test_node->parent = parent;
6480 test_node->prev = prev;
6481 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006482 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006483
6484 if (prev) prev->next = test_node;
6485 else parent->children = test_node;
6486
6487 if (next) next->prev = test_node;
6488 else parent->last = test_node;
6489
6490 /*
6491 * Insert each potential child node and check if the parent is
6492 * still valid
6493 */
6494 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6495 elements, &nb_elements, 256);
6496
6497 for (i = 0;i < nb_elements;i++) {
6498 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006499 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006500 int j;
6501
6502 for (j = 0; j < nb_valid_elements;j++)
6503 if (xmlStrEqual(elements[i], list[j])) break;
6504 list[nb_valid_elements++] = elements[i];
6505 if (nb_valid_elements >= max) break;
6506 }
6507 }
6508
6509 /*
6510 * Restore the tree structure
6511 */
6512 if (prev) prev->next = prev_next;
6513 if (next) next->prev = next_prev;
6514 parent->children = parent_childs;
6515 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006516
6517 /*
6518 * Free up the dummy node
6519 */
6520 test_node->name = name;
6521 xmlFreeNode(test_node);
6522
Owen Taylor3473f882001-02-23 17:55:21 +00006523 return(nb_valid_elements);
6524}
Daniel Veillard4432df22003-09-28 18:58:27 +00006525#endif /* LIBXML_VALID_ENABLED */
6526