blob: 59a17c668c9471b1dabe6aef7671123ad95b91c8 [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>
Daniel Veillard29b17482004-08-16 00:39:03 +000021#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <libxml/valid.h>
23#include <libxml/parser.h>
24#include <libxml/parserInternals.h>
25#include <libxml/xmlerror.h>
26#include <libxml/list.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000027#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000028
Daniel Veillard4432df22003-09-28 18:58:27 +000029static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
30 int create);
Daniel Veillarde62d36c2001-05-15 08:53:16 +000031/* #define DEBUG_VALID_ALGO */
Daniel Veillard5acfd6b2002-09-18 16:29:02 +000032/* #define DEBUG_REGEXP_ALGO */
Daniel Veillarde62d36c2001-05-15 08:53:16 +000033
Daniel Veillardf8e3db02012-09-11 13:26:36 +080034#define TODO \
Daniel Veillarda646cfd2002-09-17 21:50:03 +000035 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
37 __FILE__, __LINE__);
Owen Taylor3473f882001-02-23 17:55:21 +000038
Daniel Veillardae0765b2008-07-31 19:54:59 +000039#ifdef LIBXML_VALID_ENABLED
40static int
41xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
42 const xmlChar *value);
43#endif
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000044/************************************************************************
45 * *
46 * Error handling routines *
47 * *
48 ************************************************************************/
49
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000050/**
Daniel Veillardce9457f2003-10-05 21:33:18 +000051 * xmlVErrMemory:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000052 * @ctxt: an XML validation parser context
53 * @extra: extra informations
54 *
55 * Handle an out of memory error
56 */
57static void
Daniel Veillardce9457f2003-10-05 21:33:18 +000058xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000059{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000060 xmlGenericErrorFunc channel = NULL;
61 xmlParserCtxtPtr pctxt = NULL;
62 void *data = NULL;
63
64 if (ctxt != NULL) {
65 channel = ctxt->error;
66 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +000067 /* Use the special values to detect if it is part of a parsing
68 context */
69 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
70 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +000071 long delta = (char *) ctxt - (char *) ctxt->userData;
72 if ((delta > 0) && (delta < 250))
73 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +000074 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +000075 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000076 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000077 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000078 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000079 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
80 "Memory allocation failed : %s\n", extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000081 else
Daniel Veillard73000572003-10-11 11:26:42 +000082 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000083 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000084 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
85 "Memory allocation failed\n");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000086}
87
88/**
89 * xmlErrValid:
90 * @ctxt: an XML validation parser context
Daniel Veillardbb5abab2003-10-03 22:21:51 +000091 * @error: the error number
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000092 * @extra: extra informations
93 *
94 * Handle a validation error
95 */
David Kilzer4472c3a2016-05-13 15:13:17 +080096static void LIBXML_ATTR_FORMAT(3,0)
Daniel Veillardf88d8cf2003-12-08 10:25:02 +000097xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000098 const char *msg, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000099{
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000100 xmlGenericErrorFunc channel = NULL;
101 xmlParserCtxtPtr pctxt = NULL;
102 void *data = NULL;
103
104 if (ctxt != NULL) {
105 channel = ctxt->error;
106 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000107 /* Use the special values to detect if it is part of a parsing
108 context */
109 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
110 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +0000111 long delta = (char *) ctxt - (char *) ctxt->userData;
112 if ((delta > 0) && (delta < 250))
113 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000114 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000115 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000116 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +0000117 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000118 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000119 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
120 msg, extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000121 else
Daniel Veillard73000572003-10-11 11:26:42 +0000122 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000123 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000124 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200125 "%s", msg);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000126}
127
Daniel Veillardf54cd532004-02-25 11:52:31 +0000128#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
129/**
130 * xmlErrValidNode:
131 * @ctxt: an XML validation parser context
132 * @node: the node raising the error
133 * @error: the error number
134 * @str1: extra informations
135 * @str2: extra informations
136 * @str3: extra informations
137 *
138 * Handle a validation error, provide contextual informations
139 */
David Kilzer4472c3a2016-05-13 15:13:17 +0800140static void LIBXML_ATTR_FORMAT(4,0)
Daniel Veillardf54cd532004-02-25 11:52:31 +0000141xmlErrValidNode(xmlValidCtxtPtr ctxt,
142 xmlNodePtr node, xmlParserErrors error,
143 const char *msg, const xmlChar * str1,
144 const xmlChar * str2, const xmlChar * str3)
145{
146 xmlStructuredErrorFunc schannel = NULL;
147 xmlGenericErrorFunc channel = NULL;
148 xmlParserCtxtPtr pctxt = NULL;
149 void *data = NULL;
150
151 if (ctxt != NULL) {
152 channel = ctxt->error;
153 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000154 /* Use the special values to detect if it is part of a parsing
155 context */
156 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
157 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +0000158 long delta = (char *) ctxt - (char *) ctxt->userData;
159 if ((delta > 0) && (delta < 250))
160 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000161 }
Daniel Veillardf54cd532004-02-25 11:52:31 +0000162 }
163 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
164 XML_ERR_ERROR, NULL, 0,
165 (const char *) str1,
Nick Wellnhoferc709f3f2017-09-07 19:52:39 +0200166 (const char *) str2,
Daniel Veillardf54cd532004-02-25 11:52:31 +0000167 (const char *) str3, 0, 0, msg, str1, str2, str3);
168}
169#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
170
Daniel Veillardd61e8fb2003-10-19 21:59:17 +0000171#ifdef LIBXML_VALID_ENABLED
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000172/**
173 * xmlErrValidNodeNr:
174 * @ctxt: an XML validation parser context
175 * @node: the node raising the error
176 * @error: the error number
177 * @str1: extra informations
178 * @int2: extra informations
179 * @str3: extra informations
180 *
181 * Handle a validation error, provide contextual informations
182 */
David Kilzer4472c3a2016-05-13 15:13:17 +0800183static void LIBXML_ATTR_FORMAT(4,0)
Daniel Veillard72b9e292003-10-28 15:44:17 +0000184xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000185 xmlNodePtr node, xmlParserErrors error,
186 const char *msg, const xmlChar * str1,
187 int int2, const xmlChar * str3)
188{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000189 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000190 xmlGenericErrorFunc channel = NULL;
191 xmlParserCtxtPtr pctxt = NULL;
192 void *data = NULL;
193
194 if (ctxt != NULL) {
195 channel = ctxt->error;
196 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000197 /* Use the special values to detect if it is part of a parsing
198 context */
199 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
200 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +0000201 long delta = (char *) ctxt - (char *) ctxt->userData;
202 if ((delta > 0) && (delta < 250))
203 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000204 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000205 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000206 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000207 XML_ERR_ERROR, NULL, 0,
208 (const char *) str1,
209 (const char *) str3,
210 NULL, int2, 0, msg, str1, int2, str3);
211}
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000212
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000213/**
214 * xmlErrValidWarning:
215 * @ctxt: an XML validation parser context
216 * @node: the node raising the error
217 * @error: the error number
William M. Brackedb65a72004-02-06 07:36:04 +0000218 * @str1: extra information
219 * @str2: extra information
220 * @str3: extra information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000221 *
William M. Brackedb65a72004-02-06 07:36:04 +0000222 * Handle a validation error, provide contextual information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000223 */
David Kilzer4472c3a2016-05-13 15:13:17 +0800224static void LIBXML_ATTR_FORMAT(4,0)
William M. Brackedb65a72004-02-06 07:36:04 +0000225xmlErrValidWarning(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000226 xmlNodePtr node, xmlParserErrors error,
227 const char *msg, const xmlChar * str1,
228 const xmlChar * str2, const xmlChar * str3)
229{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000230 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000231 xmlGenericErrorFunc channel = NULL;
232 xmlParserCtxtPtr pctxt = NULL;
233 void *data = NULL;
234
235 if (ctxt != NULL) {
William M. Bracke4d526f2004-12-18 00:01:21 +0000236 channel = ctxt->warning;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000237 data = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000238 /* Use the special values to detect if it is part of a parsing
239 context */
240 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
241 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
Daniel Veillardb2dc5672006-08-22 14:45:40 +0000242 long delta = (char *) ctxt - (char *) ctxt->userData;
243 if ((delta > 0) && (delta < 250))
244 pctxt = ctxt->userData;
Daniel Veillardeff45a92004-10-29 12:10:55 +0000245 }
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000246 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000247 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000248 XML_ERR_WARNING, NULL, 0,
249 (const char *) str1,
Nick Wellnhoferc709f3f2017-09-07 19:52:39 +0200250 (const char *) str2,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000251 (const char *) str3, 0, 0, msg, str1, str2, str3);
252}
253
254
Daniel Veillardea7751d2002-12-20 00:16:24 +0000255
256#ifdef LIBXML_REGEXP_ENABLED
257/*
258 * If regexp are enabled we can do continuous validation without the
259 * need of a tree to validate the content model. this is done in each
260 * callbacks.
261 * Each xmlValidState represent the validation state associated to the
262 * set of nodes currently open from the document root to the current element.
263 */
264
265
266typedef struct _xmlValidState {
267 xmlElementPtr elemDecl; /* pointer to the content model */
268 xmlNodePtr node; /* pointer to the current node */
269 xmlRegExecCtxtPtr exec; /* regexp runtime */
270} _xmlValidState;
271
272
273static int
274vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000275 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000276 ctxt->vstateMax = 10;
277 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
278 sizeof(ctxt->vstateTab[0]));
279 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000280 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000281 return(-1);
282 }
283 }
284
285 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000286 xmlValidState *tmp;
287
288 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
289 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
290 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000291 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000292 return(-1);
293 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000294 ctxt->vstateMax *= 2;
295 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000296 }
297 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
298 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
299 ctxt->vstateTab[ctxt->vstateNr].node = node;
300 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
301 if (elemDecl->contModel == NULL)
302 xmlValidBuildContentModel(ctxt, elemDecl);
303 if (elemDecl->contModel != NULL) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800304 ctxt->vstateTab[ctxt->vstateNr].exec =
Daniel Veillardea7751d2002-12-20 00:16:24 +0000305 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
306 } else {
307 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000308 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
309 XML_ERR_INTERNAL_ERROR,
310 "Failed to build content model regexp for %s\n",
311 node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000312 }
313 }
314 return(ctxt->vstateNr++);
315}
316
317static int
318vstateVPop(xmlValidCtxtPtr ctxt) {
319 xmlElementPtr elemDecl;
320
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000321 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000322 ctxt->vstateNr--;
323 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
324 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
325 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
326 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
327 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
328 }
329 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
330 if (ctxt->vstateNr >= 1)
331 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
332 else
333 ctxt->vstate = NULL;
334 return(ctxt->vstateNr);
335}
336
337#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000338/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000339 * If regexp are not enabled, it uses a home made algorithm less
340 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000341 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000342 * only restriction is on the deepness of the tree limited by the
343 * size of the occurs bitfield
344 *
345 * this is the content of a saved state for rollbacks
346 */
347
348#define ROLLBACK_OR 0
349#define ROLLBACK_PARENT 1
350
Daniel Veillardb44025c2001-10-11 22:55:55 +0000351typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000352 xmlElementContentPtr cont; /* pointer to the content model subtree */
353 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000354 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000355 unsigned char depth; /* current depth in the overall tree */
356 unsigned char state; /* ROLLBACK_XXX */
357} _xmlValidState;
358
Daniel Veillardfc57b412002-04-29 15:50:14 +0000359#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000360#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
361#define CONT ctxt->vstate->cont
362#define NODE ctxt->vstate->node
363#define DEPTH ctxt->vstate->depth
364#define OCCURS ctxt->vstate->occurs
365#define STATE ctxt->vstate->state
366
Daniel Veillard5344c602001-12-31 16:37:34 +0000367#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
368#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000369
Daniel Veillard5344c602001-12-31 16:37:34 +0000370#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
371#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000372
373static int
374vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
375 xmlNodePtr node, unsigned char depth, long occurs,
376 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000377 int i = ctxt->vstateNr - 1;
378
Daniel Veillard940492d2002-04-15 10:15:25 +0000379 if (ctxt->vstateNr > MAX_RECURSE) {
380 return(-1);
381 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000382 if (ctxt->vstateTab == NULL) {
383 ctxt->vstateMax = 8;
384 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
385 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
386 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000387 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000388 return(-1);
389 }
390 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000391 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000392 xmlValidState *tmp;
393
394 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
395 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
396 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000397 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000398 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000399 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000400 ctxt->vstateMax *= 2;
401 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000402 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000403 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000404 /*
405 * Don't push on the stack a state already here
406 */
407 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
408 (ctxt->vstateTab[i].node == node) &&
409 (ctxt->vstateTab[i].depth == depth) &&
410 (ctxt->vstateTab[i].occurs == occurs) &&
411 (ctxt->vstateTab[i].state == state))
412 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000413 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
414 ctxt->vstateTab[ctxt->vstateNr].node = node;
415 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
416 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
417 ctxt->vstateTab[ctxt->vstateNr].state = state;
418 return(ctxt->vstateNr++);
419}
420
421static int
422vstateVPop(xmlValidCtxtPtr ctxt) {
423 if (ctxt->vstateNr <= 1) return(-1);
424 ctxt->vstateNr--;
425 ctxt->vstate = &ctxt->vstateTab[0];
426 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
427 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
428 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
429 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
430 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
431 return(ctxt->vstateNr);
432}
433
Daniel Veillard118aed72002-09-24 14:13:13 +0000434#endif /* LIBXML_REGEXP_ENABLED */
435
Daniel Veillard1c732d22002-11-30 11:22:59 +0000436static int
437nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
438{
439 if (ctxt->nodeMax <= 0) {
440 ctxt->nodeMax = 4;
441 ctxt->nodeTab =
442 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
443 sizeof(ctxt->nodeTab[0]));
444 if (ctxt->nodeTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000445 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000446 ctxt->nodeMax = 0;
447 return (0);
448 }
449 }
450 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000451 xmlNodePtr *tmp;
452 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
453 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
454 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000455 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000456 return (0);
457 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000458 ctxt->nodeMax *= 2;
459 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000460 }
461 ctxt->nodeTab[ctxt->nodeNr] = value;
462 ctxt->node = value;
463 return (ctxt->nodeNr++);
464}
465static xmlNodePtr
466nodeVPop(xmlValidCtxtPtr ctxt)
467{
468 xmlNodePtr ret;
469
470 if (ctxt->nodeNr <= 0)
Daniel Veillard24505b02005-07-28 23:49:35 +0000471 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +0000472 ctxt->nodeNr--;
473 if (ctxt->nodeNr > 0)
474 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
475 else
476 ctxt->node = NULL;
477 ret = ctxt->nodeTab[ctxt->nodeNr];
Daniel Veillard24505b02005-07-28 23:49:35 +0000478 ctxt->nodeTab[ctxt->nodeNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000479 return (ret);
480}
Owen Taylor3473f882001-02-23 17:55:21 +0000481
Owen Taylor3473f882001-02-23 17:55:21 +0000482#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000483static void
484xmlValidPrintNode(xmlNodePtr cur) {
485 if (cur == NULL) {
486 xmlGenericError(xmlGenericErrorContext, "null");
487 return;
488 }
489 switch (cur->type) {
490 case XML_ELEMENT_NODE:
491 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
492 break;
493 case XML_TEXT_NODE:
494 xmlGenericError(xmlGenericErrorContext, "text ");
495 break;
496 case XML_CDATA_SECTION_NODE:
497 xmlGenericError(xmlGenericErrorContext, "cdata ");
498 break;
499 case XML_ENTITY_REF_NODE:
500 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
501 break;
502 case XML_PI_NODE:
503 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
504 break;
505 case XML_COMMENT_NODE:
506 xmlGenericError(xmlGenericErrorContext, "comment ");
507 break;
508 case XML_ATTRIBUTE_NODE:
509 xmlGenericError(xmlGenericErrorContext, "?attr? ");
510 break;
511 case XML_ENTITY_NODE:
512 xmlGenericError(xmlGenericErrorContext, "?ent? ");
513 break;
514 case XML_DOCUMENT_NODE:
515 xmlGenericError(xmlGenericErrorContext, "?doc? ");
516 break;
517 case XML_DOCUMENT_TYPE_NODE:
518 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
519 break;
520 case XML_DOCUMENT_FRAG_NODE:
521 xmlGenericError(xmlGenericErrorContext, "?frag? ");
522 break;
523 case XML_NOTATION_NODE:
524 xmlGenericError(xmlGenericErrorContext, "?nota? ");
525 break;
526 case XML_HTML_DOCUMENT_NODE:
527 xmlGenericError(xmlGenericErrorContext, "?html? ");
528 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000529#ifdef LIBXML_DOCB_ENABLED
530 case XML_DOCB_DOCUMENT_NODE:
531 xmlGenericError(xmlGenericErrorContext, "?docb? ");
532 break;
533#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000534 case XML_DTD_NODE:
535 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
536 break;
537 case XML_ELEMENT_DECL:
538 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
539 break;
540 case XML_ATTRIBUTE_DECL:
541 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
542 break;
543 case XML_ENTITY_DECL:
544 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
545 break;
546 case XML_NAMESPACE_DECL:
547 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
548 break;
549 case XML_XINCLUDE_START:
550 xmlGenericError(xmlGenericErrorContext, "incstart ");
551 break;
552 case XML_XINCLUDE_END:
553 xmlGenericError(xmlGenericErrorContext, "incend ");
554 break;
555 }
556}
557
558static void
559xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000560 if (cur == NULL)
561 xmlGenericError(xmlGenericErrorContext, "null ");
562 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000563 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000564 cur = cur->next;
565 }
566}
567
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000568static void
569xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000570 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000571
572 expr[0] = 0;
573 xmlGenericError(xmlGenericErrorContext, "valid: ");
574 xmlValidPrintNodeList(cur);
575 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000576 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000577 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
578}
579
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000580static void
581xmlValidDebugState(xmlValidStatePtr state) {
582 xmlGenericError(xmlGenericErrorContext, "(");
583 if (state->cont == NULL)
584 xmlGenericError(xmlGenericErrorContext, "null,");
585 else
586 switch (state->cont->type) {
587 case XML_ELEMENT_CONTENT_PCDATA:
588 xmlGenericError(xmlGenericErrorContext, "pcdata,");
589 break;
590 case XML_ELEMENT_CONTENT_ELEMENT:
591 xmlGenericError(xmlGenericErrorContext, "%s,",
592 state->cont->name);
593 break;
594 case XML_ELEMENT_CONTENT_SEQ:
595 xmlGenericError(xmlGenericErrorContext, "seq,");
596 break;
597 case XML_ELEMENT_CONTENT_OR:
598 xmlGenericError(xmlGenericErrorContext, "or,");
599 break;
600 }
601 xmlValidPrintNode(state->node);
602 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
603 state->depth, state->occurs, state->state);
604}
605
606static void
607xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
608 int i, j;
609
610 xmlGenericError(xmlGenericErrorContext, "state: ");
611 xmlValidDebugState(ctxt->vstate);
612 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
613 ctxt->vstateNr - 1);
614 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
615 xmlValidDebugState(&ctxt->vstateTab[j]);
616 xmlGenericError(xmlGenericErrorContext, "\n");
617}
618
619/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000620#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000621 *****/
622
623#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000624#define DEBUG_VALID_MSG(m) \
625 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800626
Owen Taylor3473f882001-02-23 17:55:21 +0000627#else
628#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000629#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000630#endif
631
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000632/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000633
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000634
Owen Taylor3473f882001-02-23 17:55:21 +0000635#define CHECK_DTD \
636 if (doc == NULL) return(0); \
637 else if ((doc->intSubset == NULL) && \
638 (doc->extSubset == NULL)) return(0)
639
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000640#ifdef LIBXML_REGEXP_ENABLED
641
642/************************************************************************
643 * *
644 * Content model validation based on the regexps *
645 * *
646 ************************************************************************/
647
648/**
649 * xmlValidBuildAContentModel:
650 * @content: the content model
651 * @ctxt: the schema parser context
652 * @name: the element name whose content is being built
653 *
654 * Generate the automata sequence needed for that type
655 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000656 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000657 */
658static int
659xmlValidBuildAContentModel(xmlElementContentPtr content,
660 xmlValidCtxtPtr ctxt,
661 const xmlChar *name) {
662 if (content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000663 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
664 "Found NULL content in content model of %s\n",
665 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000666 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000667 }
668 switch (content->type) {
669 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000670 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
671 "Found PCDATA in content model of %s\n",
672 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000673 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000674 break;
675 case XML_ELEMENT_CONTENT_ELEMENT: {
676 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000677 xmlChar fn[50];
678 xmlChar *fullname;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800679
Daniel Veillardc00cda82003-04-07 10:22:39 +0000680 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
681 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000682 xmlVErrMemory(ctxt, "Building content model");
Daniel Veillardc00cda82003-04-07 10:22:39 +0000683 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000684 }
685
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000686 switch (content->ocur) {
687 case XML_ELEMENT_CONTENT_ONCE:
688 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000689 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000690 break;
691 case XML_ELEMENT_CONTENT_OPT:
692 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000693 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000694 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
695 break;
696 case XML_ELEMENT_CONTENT_PLUS:
697 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000698 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000699 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000700 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000701 break;
702 case XML_ELEMENT_CONTENT_MULT:
William M. Brack8b0cbb02004-04-17 13:31:06 +0000703 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800704 ctxt->state, NULL);
William M. Brack8b0cbb02004-04-17 13:31:06 +0000705 xmlAutomataNewTransition(ctxt->am,
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800706 ctxt->state, ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000707 break;
708 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000709 if ((fullname != fn) && (fullname != content->name))
710 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000711 break;
712 }
713 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000714 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000715 xmlElementContentOccur ocur;
716
717 /*
718 * Simply iterate over the content
719 */
720 oldstate = ctxt->state;
721 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000722 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
723 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
724 oldstate = ctxt->state;
725 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000726 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000727 xmlValidBuildAContentModel(content->c1, ctxt, name);
728 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000729 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
730 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
731 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000732 oldend = ctxt->state;
733 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000734 switch (ocur) {
735 case XML_ELEMENT_CONTENT_ONCE:
736 break;
737 case XML_ELEMENT_CONTENT_OPT:
738 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
739 break;
740 case XML_ELEMENT_CONTENT_MULT:
741 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000742 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000743 break;
744 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000745 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000746 break;
747 }
748 break;
749 }
750 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000751 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000752 xmlElementContentOccur ocur;
753
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000754 ocur = content->ocur;
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800755 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000756 (ocur == XML_ELEMENT_CONTENT_MULT)) {
757 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
758 ctxt->state, NULL);
759 }
760 oldstate = ctxt->state;
761 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000762
763 /*
764 * iterate over the subtypes and remerge the end with an
765 * epsilon transition
766 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000767 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000768 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000769 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000770 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000771 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000772 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
773 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000774 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000775 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000776 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
777 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000778 switch (ocur) {
779 case XML_ELEMENT_CONTENT_ONCE:
780 break;
781 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000782 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000783 break;
784 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000785 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
786 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000787 break;
788 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000789 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000790 break;
791 }
792 break;
793 }
794 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000795 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
796 "ContentModel broken for element %s\n",
797 (const char *) name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000798 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000799 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000800 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000801}
802/**
803 * xmlValidBuildContentModel:
804 * @ctxt: a validation context
805 * @elem: an element declaration node
806 *
807 * (Re)Build the automata associated to the content model of this
808 * element
809 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000810 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000811 */
812int
813xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000814
815 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000816 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000817 if (elem->type != XML_ELEMENT_DECL)
818 return(0);
819 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
820 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000821 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000822 if (elem->contModel != NULL) {
823 if (!xmlRegexpIsDeterminist(elem->contModel)) {
824 ctxt->valid = 0;
825 return(0);
826 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000827 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000828 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000829
830 ctxt->am = xmlNewAutomata();
831 if (ctxt->am == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000832 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
833 XML_ERR_INTERNAL_ERROR,
834 "Cannot create automata for element %s\n",
835 elem->name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000836 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000837 }
William M. Brack78637da2003-07-31 14:47:38 +0000838 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000839 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
840 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000841 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000842 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000843 char expr[5000];
844 expr[0] = 0;
845 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000846 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
847 XML_DTD_CONTENT_NOT_DETERMINIST,
848 "Content model of %s is not determinist: %s\n",
849 elem->name, BAD_CAST expr, NULL);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000850#ifdef DEBUG_REGEXP_ALGO
851 xmlRegexpPrint(stderr, elem->contModel);
852#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000853 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000854 ctxt->state = NULL;
855 xmlFreeAutomata(ctxt->am);
856 ctxt->am = NULL;
857 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000858 }
859 ctxt->state = NULL;
860 xmlFreeAutomata(ctxt->am);
861 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000862 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000863}
864
865#endif /* LIBXML_REGEXP_ENABLED */
866
Owen Taylor3473f882001-02-23 17:55:21 +0000867/****************************************************************
868 * *
869 * Util functions for data allocation/deallocation *
870 * *
871 ****************************************************************/
872
873/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000874 * xmlNewValidCtxt:
875 *
876 * Allocate a validation context structure.
877 *
878 * Returns NULL if not, otherwise the new validation context structure
879 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000880xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000881 xmlValidCtxtPtr ret;
882
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000883 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000884 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000885 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000886 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000887
888 (void) memset(ret, 0, sizeof (xmlValidCtxt));
889
890 return (ret);
891}
892
893/**
894 * xmlFreeValidCtxt:
895 * @cur: the validation context to free
896 *
897 * Free a validation context structure.
898 */
899void
900xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
Daniel Veillardc0be74b2004-11-03 19:16:55 +0000901 if (cur->vstateTab != NULL)
902 xmlFree(cur->vstateTab);
903 if (cur->nodeTab != NULL)
904 xmlFree(cur->nodeTab);
Daniel Veillarda37aab82003-06-09 09:10:36 +0000905 xmlFree(cur);
906}
907
Daniel Veillard4432df22003-09-28 18:58:27 +0000908#endif /* LIBXML_VALID_ENABLED */
909
Daniel Veillarda37aab82003-06-09 09:10:36 +0000910/**
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000911 * xmlNewDocElementContent:
912 * @doc: the document
Owen Taylor3473f882001-02-23 17:55:21 +0000913 * @name: the subelement name or NULL
914 * @type: the type of element content decl
915 *
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000916 * Allocate an element content structure for the document.
Owen Taylor3473f882001-02-23 17:55:21 +0000917 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000918 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000919 */
920xmlElementContentPtr
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000921xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
922 xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000923 xmlElementContentPtr ret;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000924 xmlDictPtr dict = NULL;
925
926 if (doc != NULL)
927 dict = doc->dict;
Owen Taylor3473f882001-02-23 17:55:21 +0000928
929 switch(type) {
930 case XML_ELEMENT_CONTENT_ELEMENT:
931 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000932 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
933 "xmlNewElementContent : name == NULL !\n",
934 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000935 }
936 break;
937 case XML_ELEMENT_CONTENT_PCDATA:
938 case XML_ELEMENT_CONTENT_SEQ:
939 case XML_ELEMENT_CONTENT_OR:
940 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000941 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
942 "xmlNewElementContent : name != NULL !\n",
943 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000944 }
945 break;
946 default:
Daniel Veillardf8e3db02012-09-11 13:26:36 +0800947 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000948 "Internal: ELEMENT content corrupted invalid type\n",
949 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000950 return(NULL);
951 }
952 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
953 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000954 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000955 return(NULL);
956 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000957 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000958 ret->type = type;
959 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000960 if (name != NULL) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000961 int l;
962 const xmlChar *tmp;
963
964 tmp = xmlSplitQName3(name, &l);
965 if (tmp == NULL) {
966 if (dict == NULL)
967 ret->name = xmlStrdup(name);
968 else
969 ret->name = xmlDictLookup(dict, name, -1);
970 } else {
971 if (dict == NULL) {
972 ret->prefix = xmlStrndup(name, l);
973 ret->name = xmlStrdup(tmp);
974 } else {
975 ret->prefix = xmlDictLookup(dict, name, l);
976 ret->name = xmlDictLookup(dict, tmp, -1);
977 }
978 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000979 }
Daniel Veillardcee2b3a2005-01-25 00:22:52 +0000980 return(ret);
981}
982
983/**
984 * xmlNewElementContent:
985 * @name: the subelement name or NULL
986 * @type: the type of element content decl
987 *
988 * Allocate an element content structure.
989 * Deprecated in favor of xmlNewDocElementContent
990 *
991 * Returns NULL if not, otherwise the new element content structure
992 */
993xmlElementContentPtr
994xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
995 return(xmlNewDocElementContent(NULL, name, type));
996}
997
998/**
999 * xmlCopyDocElementContent:
1000 * @doc: the document owning the element declaration
1001 * @cur: An element content pointer.
1002 *
1003 * Build a copy of an element content description.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001004 *
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001005 * Returns the new xmlElementContentPtr or NULL in case of error.
1006 */
1007xmlElementContentPtr
1008xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1009 xmlElementContentPtr ret = NULL, prev = NULL, tmp;
1010 xmlDictPtr dict = NULL;
1011
1012 if (cur == NULL) return(NULL);
1013
1014 if (doc != NULL)
1015 dict = doc->dict;
1016
1017 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1018 if (ret == NULL) {
1019 xmlVErrMemory(NULL, "malloc failed");
1020 return(NULL);
1021 }
1022 memset(ret, 0, sizeof(xmlElementContent));
1023 ret->type = cur->type;
1024 ret->ocur = cur->ocur;
1025 if (cur->name != NULL) {
1026 if (dict)
1027 ret->name = xmlDictLookup(dict, cur->name, -1);
1028 else
1029 ret->name = xmlStrdup(cur->name);
1030 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001031
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001032 if (cur->prefix != NULL) {
1033 if (dict)
1034 ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1035 else
1036 ret->prefix = xmlStrdup(cur->prefix);
1037 }
1038 if (cur->c1 != NULL)
1039 ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1040 if (ret->c1 != NULL)
1041 ret->c1->parent = ret;
1042 if (cur->c2 != NULL) {
1043 prev = ret;
1044 cur = cur->c2;
1045 while (cur != NULL) {
1046 tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1047 if (tmp == NULL) {
1048 xmlVErrMemory(NULL, "malloc failed");
1049 return(ret);
1050 }
1051 memset(tmp, 0, sizeof(xmlElementContent));
1052 tmp->type = cur->type;
1053 tmp->ocur = cur->ocur;
1054 prev->c2 = tmp;
1055 if (cur->name != NULL) {
1056 if (dict)
1057 tmp->name = xmlDictLookup(dict, cur->name, -1);
1058 else
1059 tmp->name = xmlStrdup(cur->name);
1060 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001061
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001062 if (cur->prefix != NULL) {
1063 if (dict)
1064 tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1065 else
1066 tmp->prefix = xmlStrdup(cur->prefix);
1067 }
1068 if (cur->c1 != NULL)
1069 tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1070 if (tmp->c1 != NULL)
1071 tmp->c1->parent = ret;
1072 prev = tmp;
1073 cur = cur->c2;
1074 }
1075 }
Owen Taylor3473f882001-02-23 17:55:21 +00001076 return(ret);
1077}
1078
1079/**
1080 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +00001081 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +00001082 *
1083 * Build a copy of an element content description.
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001084 * Deprecated, use xmlCopyDocElementContent instead
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001085 *
Owen Taylor3473f882001-02-23 17:55:21 +00001086 * Returns the new xmlElementContentPtr or NULL in case of error.
1087 */
1088xmlElementContentPtr
1089xmlCopyElementContent(xmlElementContentPtr cur) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001090 return(xmlCopyDocElementContent(NULL, cur));
1091}
Owen Taylor3473f882001-02-23 17:55:21 +00001092
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001093/**
1094 * xmlFreeDocElementContent:
1095 * @doc: the document owning the element declaration
1096 * @cur: the element content tree to free
1097 *
1098 * Free an element content structure. The whole subtree is removed.
1099 */
1100void
1101xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1102 xmlElementContentPtr next;
1103 xmlDictPtr dict = NULL;
1104
1105 if (doc != NULL)
1106 dict = doc->dict;
1107
1108 while (cur != NULL) {
1109 next = cur->c2;
1110 switch (cur->type) {
1111 case XML_ELEMENT_CONTENT_PCDATA:
1112 case XML_ELEMENT_CONTENT_ELEMENT:
1113 case XML_ELEMENT_CONTENT_SEQ:
1114 case XML_ELEMENT_CONTENT_OR:
1115 break;
1116 default:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001117 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001118 "Internal: ELEMENT content corrupted invalid type\n",
1119 NULL);
1120 return;
1121 }
1122 if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1);
1123 if (dict) {
1124 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1125 xmlFree((xmlChar *) cur->name);
1126 if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1127 xmlFree((xmlChar *) cur->prefix);
1128 } else {
1129 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1130 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1131 }
1132 xmlFree(cur);
1133 cur = next;
Owen Taylor3473f882001-02-23 17:55:21 +00001134 }
Owen Taylor3473f882001-02-23 17:55:21 +00001135}
1136
1137/**
1138 * xmlFreeElementContent:
1139 * @cur: the element content tree to free
1140 *
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001141 * Free an element content structure. The whole subtree is removed.
1142 * Deprecated, use xmlFreeDocElementContent instead
Owen Taylor3473f882001-02-23 17:55:21 +00001143 */
1144void
1145xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001146 xmlFreeDocElementContent(NULL, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001147}
1148
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001149#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001150/**
1151 * xmlDumpElementContent:
1152 * @buf: An XML buffer
1153 * @content: An element table
1154 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1155 *
1156 * This will dump the content of the element table as an XML DTD definition
1157 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001158static void
Owen Taylor3473f882001-02-23 17:55:21 +00001159xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1160 if (content == NULL) return;
1161
1162 if (glob) xmlBufferWriteChar(buf, "(");
1163 switch (content->type) {
1164 case XML_ELEMENT_CONTENT_PCDATA:
1165 xmlBufferWriteChar(buf, "#PCDATA");
1166 break;
1167 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001168 if (content->prefix != NULL) {
1169 xmlBufferWriteCHAR(buf, content->prefix);
1170 xmlBufferWriteChar(buf, ":");
1171 }
Owen Taylor3473f882001-02-23 17:55:21 +00001172 xmlBufferWriteCHAR(buf, content->name);
1173 break;
1174 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard94691dc2017-06-07 16:47:36 +02001175 if ((content->c1 != NULL) &&
1176 ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1177 (content->c1->type == XML_ELEMENT_CONTENT_SEQ)))
Owen Taylor3473f882001-02-23 17:55:21 +00001178 xmlDumpElementContent(buf, content->c1, 1);
1179 else
1180 xmlDumpElementContent(buf, content->c1, 0);
1181 xmlBufferWriteChar(buf, " , ");
Daniel Veillard94691dc2017-06-07 16:47:36 +02001182 if ((content->c2 != NULL) &&
1183 ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1184 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
1185 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE))))
Owen Taylor3473f882001-02-23 17:55:21 +00001186 xmlDumpElementContent(buf, content->c2, 1);
1187 else
1188 xmlDumpElementContent(buf, content->c2, 0);
1189 break;
1190 case XML_ELEMENT_CONTENT_OR:
Daniel Veillard94691dc2017-06-07 16:47:36 +02001191 if ((content->c1 != NULL) &&
1192 ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1193 (content->c1->type == XML_ELEMENT_CONTENT_SEQ)))
Owen Taylor3473f882001-02-23 17:55:21 +00001194 xmlDumpElementContent(buf, content->c1, 1);
1195 else
1196 xmlDumpElementContent(buf, content->c1, 0);
1197 xmlBufferWriteChar(buf, " | ");
Daniel Veillard94691dc2017-06-07 16:47:36 +02001198 if ((content->c2 != NULL) &&
1199 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1200 ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
1201 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE))))
Owen Taylor3473f882001-02-23 17:55:21 +00001202 xmlDumpElementContent(buf, content->c2, 1);
1203 else
1204 xmlDumpElementContent(buf, content->c2, 0);
1205 break;
1206 default:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001207 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001208 "Internal: ELEMENT content corrupted invalid type\n",
1209 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001210 }
1211 if (glob)
1212 xmlBufferWriteChar(buf, ")");
1213 switch (content->ocur) {
1214 case XML_ELEMENT_CONTENT_ONCE:
1215 break;
1216 case XML_ELEMENT_CONTENT_OPT:
1217 xmlBufferWriteChar(buf, "?");
1218 break;
1219 case XML_ELEMENT_CONTENT_MULT:
1220 xmlBufferWriteChar(buf, "*");
1221 break;
1222 case XML_ELEMENT_CONTENT_PLUS:
1223 xmlBufferWriteChar(buf, "+");
1224 break;
1225 }
1226}
1227
1228/**
1229 * xmlSprintfElementContent:
1230 * @buf: an output buffer
1231 * @content: An element table
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001232 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001233 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001234 * Deprecated, unsafe, use xmlSnprintfElementContent
1235 */
1236void
1237xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1238 xmlElementContentPtr content ATTRIBUTE_UNUSED,
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001239 int englob ATTRIBUTE_UNUSED) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001240}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001241#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001242
1243/**
1244 * xmlSnprintfElementContent:
1245 * @buf: an output buffer
1246 * @size: the buffer size
1247 * @content: An element table
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001248 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
Daniel Veillardd3d06722001-08-15 12:06:36 +00001249 *
Owen Taylor3473f882001-02-23 17:55:21 +00001250 * This will dump the content of the element content definition
1251 * Intended just for the debug routine
1252 */
1253void
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001254xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001255 int len;
1256
Owen Taylor3473f882001-02-23 17:55:21 +00001257 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001258 len = strlen(buf);
1259 if (size - len < 50) {
1260 if ((size - len > 4) && (buf[len - 1] != '.'))
1261 strcat(buf, " ...");
1262 return;
1263 }
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001264 if (englob) strcat(buf, "(");
Owen Taylor3473f882001-02-23 17:55:21 +00001265 switch (content->type) {
1266 case XML_ELEMENT_CONTENT_PCDATA:
1267 strcat(buf, "#PCDATA");
1268 break;
Nick Wellnhofer932cc982017-06-03 02:01:29 +02001269 case XML_ELEMENT_CONTENT_ELEMENT: {
1270 int qnameLen = xmlStrlen(content->name);
1271
1272 if (content->prefix != NULL)
1273 qnameLen += xmlStrlen(content->prefix) + 1;
1274 if (size - len < qnameLen + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001275 strcat(buf, " ...");
1276 return;
1277 }
Nick Wellnhofer932cc982017-06-03 02:01:29 +02001278 if (content->prefix != NULL) {
1279 strcat(buf, (char *) content->prefix);
1280 strcat(buf, ":");
1281 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001282 if (content->name != NULL)
1283 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001284 break;
Nick Wellnhofer932cc982017-06-03 02:01:29 +02001285 }
Owen Taylor3473f882001-02-23 17:55:21 +00001286 case XML_ELEMENT_CONTENT_SEQ:
1287 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1288 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001289 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001290 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001291 xmlSnprintfElementContent(buf, size, content->c1, 0);
1292 len = strlen(buf);
1293 if (size - len < 50) {
1294 if ((size - len > 4) && (buf[len - 1] != '.'))
1295 strcat(buf, " ...");
1296 return;
1297 }
Owen Taylor3473f882001-02-23 17:55:21 +00001298 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001299 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1300 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1301 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001302 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001303 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001304 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001305 break;
1306 case XML_ELEMENT_CONTENT_OR:
1307 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1308 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001309 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001310 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001311 xmlSnprintfElementContent(buf, size, content->c1, 0);
1312 len = strlen(buf);
1313 if (size - len < 50) {
1314 if ((size - len > 4) && (buf[len - 1] != '.'))
1315 strcat(buf, " ...");
1316 return;
1317 }
Owen Taylor3473f882001-02-23 17:55:21 +00001318 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001319 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1320 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1321 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001322 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001323 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001324 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001325 break;
1326 }
Nick Wellnhofer932cc982017-06-03 02:01:29 +02001327 if (size - strlen(buf) <= 2) return;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001328 if (englob)
Owen Taylor3473f882001-02-23 17:55:21 +00001329 strcat(buf, ")");
1330 switch (content->ocur) {
1331 case XML_ELEMENT_CONTENT_ONCE:
1332 break;
1333 case XML_ELEMENT_CONTENT_OPT:
1334 strcat(buf, "?");
1335 break;
1336 case XML_ELEMENT_CONTENT_MULT:
1337 strcat(buf, "*");
1338 break;
1339 case XML_ELEMENT_CONTENT_PLUS:
1340 strcat(buf, "+");
1341 break;
1342 }
1343}
1344
1345/****************************************************************
1346 * *
1347 * Registration of DTD declarations *
1348 * *
1349 ****************************************************************/
1350
1351/**
Owen Taylor3473f882001-02-23 17:55:21 +00001352 * xmlFreeElement:
1353 * @elem: An element
1354 *
1355 * Deallocate the memory used by an element definition
1356 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001357static void
Owen Taylor3473f882001-02-23 17:55:21 +00001358xmlFreeElement(xmlElementPtr elem) {
1359 if (elem == NULL) return;
1360 xmlUnlinkNode((xmlNodePtr) elem);
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001361 xmlFreeDocElementContent(elem->doc, elem->content);
Owen Taylor3473f882001-02-23 17:55:21 +00001362 if (elem->name != NULL)
1363 xmlFree((xmlChar *) elem->name);
1364 if (elem->prefix != NULL)
1365 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001366#ifdef LIBXML_REGEXP_ENABLED
1367 if (elem->contModel != NULL)
1368 xmlRegFreeRegexp(elem->contModel);
1369#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001370 xmlFree(elem);
1371}
1372
1373
1374/**
1375 * xmlAddElementDecl:
1376 * @ctxt: the validation context
1377 * @dtd: pointer to the DTD
1378 * @name: the entity name
1379 * @type: the element type
1380 * @content: the element content tree or NULL
1381 *
1382 * Register a new element declaration
1383 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001384 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001385 */
1386xmlElementPtr
William M. Brackedb65a72004-02-06 07:36:04 +00001387xmlAddElementDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001388 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001389 xmlElementTypeVal type,
1390 xmlElementContentPtr content) {
1391 xmlElementPtr ret;
1392 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001393 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001394 xmlChar *ns, *uqname;
1395
1396 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001397 return(NULL);
1398 }
1399 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001400 return(NULL);
1401 }
Daniel Veillard316a5c32005-01-23 22:56:39 +00001402
Owen Taylor3473f882001-02-23 17:55:21 +00001403 switch (type) {
1404 case XML_ELEMENT_TYPE_EMPTY:
1405 if (content != NULL) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001406 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001407 "xmlAddElementDecl: content != NULL for EMPTY\n",
1408 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001409 return(NULL);
1410 }
1411 break;
1412 case XML_ELEMENT_TYPE_ANY:
1413 if (content != NULL) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001414 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001415 "xmlAddElementDecl: content != NULL for ANY\n",
1416 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001417 return(NULL);
1418 }
1419 break;
1420 case XML_ELEMENT_TYPE_MIXED:
1421 if (content == NULL) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001422 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001423 "xmlAddElementDecl: content == NULL for MIXED\n",
1424 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001425 return(NULL);
1426 }
1427 break;
1428 case XML_ELEMENT_TYPE_ELEMENT:
1429 if (content == NULL) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001430 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001431 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1432 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001433 return(NULL);
1434 }
1435 break;
1436 default:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001437 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001438 "Internal: ELEMENT decl corrupted invalid type\n",
1439 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001440 return(NULL);
1441 }
1442
1443 /*
1444 * check if name is a QName
1445 */
1446 uqname = xmlSplitQName2(name, &ns);
1447 if (uqname != NULL)
1448 name = uqname;
1449
1450 /*
1451 * Create the Element table if needed.
1452 */
1453 table = (xmlElementTablePtr) dtd->elements;
1454 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00001455 xmlDictPtr dict = NULL;
1456
1457 if (dtd->doc != NULL)
1458 dict = dtd->doc->dict;
1459 table = xmlHashCreateDict(0, dict);
Owen Taylor3473f882001-02-23 17:55:21 +00001460 dtd->elements = (void *) table;
1461 }
1462 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001463 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001464 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001465 if (uqname != NULL)
1466 xmlFree(uqname);
1467 if (ns != NULL)
1468 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001469 return(NULL);
1470 }
1471
Daniel Veillarda10efa82001-04-18 13:09:01 +00001472 /*
1473 * lookup old attributes inserted on an undefined element in the
1474 * internal subset.
1475 */
1476 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1477 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1478 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1479 oldAttributes = ret->attributes;
1480 ret->attributes = NULL;
1481 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1482 xmlFreeElement(ret);
1483 }
Owen Taylor3473f882001-02-23 17:55:21 +00001484 }
Owen Taylor3473f882001-02-23 17:55:21 +00001485
1486 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001487 * The element may already be present if one of its attribute
1488 * was registered first
1489 */
1490 ret = xmlHashLookup2(table, name, ns);
1491 if (ret != NULL) {
1492 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001493#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001494 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001495 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001496 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001497 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1498 "Redefinition of element %s\n",
1499 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001500#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001501 if (uqname != NULL)
1502 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001503 if (ns != NULL)
1504 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001505 return(NULL);
1506 }
William M. Brackd6e347e2005-04-15 01:34:41 +00001507 if (ns != NULL) {
1508 xmlFree(ns);
1509 ns = NULL;
1510 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001511 } else {
1512 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1513 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001514 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001515 if (uqname != NULL)
1516 xmlFree(uqname);
1517 if (ns != NULL)
1518 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001519 return(NULL);
1520 }
1521 memset(ret, 0, sizeof(xmlElement));
1522 ret->type = XML_ELEMENT_DECL;
1523
1524 /*
1525 * fill the structure.
1526 */
1527 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001528 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001529 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001530 if (uqname != NULL)
1531 xmlFree(uqname);
1532 if (ns != NULL)
1533 xmlFree(ns);
1534 xmlFree(ret);
1535 return(NULL);
1536 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001537 ret->prefix = ns;
1538
1539 /*
1540 * Validity Check:
1541 * Insertion must not fail
1542 */
1543 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001544#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001545 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001546 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001547 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001548 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1549 "Redefinition of element %s\n",
1550 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001551#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001552 xmlFreeElement(ret);
1553 if (uqname != NULL)
1554 xmlFree(uqname);
1555 return(NULL);
1556 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001557 /*
1558 * For new element, may have attributes from earlier
1559 * definition in internal subset
1560 */
1561 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001562 }
1563
1564 /*
1565 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001566 */
1567 ret->etype = type;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001568 /*
1569 * Avoid a stupid copy when called by the parser
1570 * and flag it by setting a special parent value
1571 * so the parser doesn't unallocate it.
1572 */
Daniel Veillardc394f732005-01-26 00:04:52 +00001573 if ((ctxt != NULL) &&
1574 ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
1575 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001576 ret->content = content;
1577 if (content != NULL)
1578 content->parent = (xmlElementContentPtr) 1;
1579 } else {
1580 ret->content = xmlCopyDocElementContent(dtd->doc, content);
1581 }
Owen Taylor3473f882001-02-23 17:55:21 +00001582
1583 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001584 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001585 */
1586 ret->parent = dtd;
1587 ret->doc = dtd->doc;
1588 if (dtd->last == NULL) {
1589 dtd->children = dtd->last = (xmlNodePtr) ret;
1590 } else {
1591 dtd->last->next = (xmlNodePtr) ret;
1592 ret->prev = dtd->last;
1593 dtd->last = (xmlNodePtr) ret;
1594 }
1595 if (uqname != NULL)
1596 xmlFree(uqname);
1597 return(ret);
1598}
1599
1600/**
1601 * xmlFreeElementTable:
1602 * @table: An element table
1603 *
1604 * Deallocate the memory used by an element hash table.
1605 */
1606void
1607xmlFreeElementTable(xmlElementTablePtr table) {
1608 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1609}
1610
Daniel Veillard652327a2003-09-29 18:02:38 +00001611#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001612/**
1613 * xmlCopyElement:
1614 * @elem: An element
1615 *
1616 * Build a copy of an element.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001617 *
Owen Taylor3473f882001-02-23 17:55:21 +00001618 * Returns the new xmlElementPtr or NULL in case of error.
1619 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001620static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001621xmlCopyElement(xmlElementPtr elem) {
1622 xmlElementPtr cur;
1623
1624 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1625 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001626 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001627 return(NULL);
1628 }
1629 memset(cur, 0, sizeof(xmlElement));
1630 cur->type = XML_ELEMENT_DECL;
1631 cur->etype = elem->etype;
1632 if (elem->name != NULL)
1633 cur->name = xmlStrdup(elem->name);
1634 else
1635 cur->name = NULL;
1636 if (elem->prefix != NULL)
1637 cur->prefix = xmlStrdup(elem->prefix);
1638 else
1639 cur->prefix = NULL;
1640 cur->content = xmlCopyElementContent(elem->content);
1641 /* TODO : rebuild the attribute list on the copy */
1642 cur->attributes = NULL;
1643 return(cur);
1644}
1645
1646/**
1647 * xmlCopyElementTable:
1648 * @table: An element table
1649 *
1650 * Build a copy of an element table.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001651 *
Owen Taylor3473f882001-02-23 17:55:21 +00001652 * Returns the new xmlElementTablePtr or NULL in case of error.
1653 */
1654xmlElementTablePtr
1655xmlCopyElementTable(xmlElementTablePtr table) {
1656 return((xmlElementTablePtr) xmlHashCopy(table,
1657 (xmlHashCopier) xmlCopyElement));
1658}
Daniel Veillard652327a2003-09-29 18:02:38 +00001659#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001660
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001661#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001662/**
1663 * xmlDumpElementDecl:
1664 * @buf: the XML buffer output
1665 * @elem: An element table
1666 *
1667 * This will dump the content of the element declaration as an XML
1668 * DTD definition
1669 */
1670void
1671xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001672 if ((buf == NULL) || (elem == NULL))
1673 return;
Owen Taylor3473f882001-02-23 17:55:21 +00001674 switch (elem->etype) {
1675 case XML_ELEMENT_TYPE_EMPTY:
1676 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001677 if (elem->prefix != NULL) {
1678 xmlBufferWriteCHAR(buf, elem->prefix);
1679 xmlBufferWriteChar(buf, ":");
1680 }
Owen Taylor3473f882001-02-23 17:55:21 +00001681 xmlBufferWriteCHAR(buf, elem->name);
1682 xmlBufferWriteChar(buf, " EMPTY>\n");
1683 break;
1684 case XML_ELEMENT_TYPE_ANY:
1685 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001686 if (elem->prefix != NULL) {
1687 xmlBufferWriteCHAR(buf, elem->prefix);
1688 xmlBufferWriteChar(buf, ":");
1689 }
Owen Taylor3473f882001-02-23 17:55:21 +00001690 xmlBufferWriteCHAR(buf, elem->name);
1691 xmlBufferWriteChar(buf, " ANY>\n");
1692 break;
1693 case XML_ELEMENT_TYPE_MIXED:
1694 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001695 if (elem->prefix != NULL) {
1696 xmlBufferWriteCHAR(buf, elem->prefix);
1697 xmlBufferWriteChar(buf, ":");
1698 }
Owen Taylor3473f882001-02-23 17:55:21 +00001699 xmlBufferWriteCHAR(buf, elem->name);
1700 xmlBufferWriteChar(buf, " ");
1701 xmlDumpElementContent(buf, elem->content, 1);
1702 xmlBufferWriteChar(buf, ">\n");
1703 break;
1704 case XML_ELEMENT_TYPE_ELEMENT:
1705 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001706 if (elem->prefix != NULL) {
1707 xmlBufferWriteCHAR(buf, elem->prefix);
1708 xmlBufferWriteChar(buf, ":");
1709 }
Owen Taylor3473f882001-02-23 17:55:21 +00001710 xmlBufferWriteCHAR(buf, elem->name);
1711 xmlBufferWriteChar(buf, " ");
1712 xmlDumpElementContent(buf, elem->content, 1);
1713 xmlBufferWriteChar(buf, ">\n");
1714 break;
1715 default:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001716 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001717 "Internal: ELEMENT struct corrupted invalid type\n",
1718 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001719 }
1720}
1721
1722/**
William M. Brack9e660592003-10-20 14:56:06 +00001723 * xmlDumpElementDeclScan:
1724 * @elem: An element table
1725 * @buf: the XML buffer output
1726 *
1727 * This routine is used by the hash scan function. It just reverses
1728 * the arguments.
1729 */
1730static void
1731xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1732 xmlDumpElementDecl(buf, elem);
1733}
1734
1735/**
Owen Taylor3473f882001-02-23 17:55:21 +00001736 * xmlDumpElementTable:
1737 * @buf: the XML buffer output
1738 * @table: An element table
1739 *
1740 * This will dump the content of the element table as an XML DTD definition
1741 */
1742void
1743xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001744 if ((buf == NULL) || (table == NULL))
1745 return;
William M. Brack9e660592003-10-20 14:56:06 +00001746 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001747}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001748#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001749
1750/**
1751 * xmlCreateEnumeration:
1752 * @name: the enumeration name or NULL
1753 *
1754 * create and initialize an enumeration attribute node.
1755 *
1756 * Returns the xmlEnumerationPtr just created or NULL in case
1757 * of error.
1758 */
1759xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001760xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001761 xmlEnumerationPtr ret;
1762
1763 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1764 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001765 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001766 return(NULL);
1767 }
1768 memset(ret, 0, sizeof(xmlEnumeration));
1769
1770 if (name != NULL)
1771 ret->name = xmlStrdup(name);
1772 return(ret);
1773}
1774
1775/**
1776 * xmlFreeEnumeration:
1777 * @cur: the tree to free.
1778 *
1779 * free an enumeration attribute node (recursive).
1780 */
1781void
1782xmlFreeEnumeration(xmlEnumerationPtr cur) {
1783 if (cur == NULL) return;
1784
1785 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1786
1787 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001788 xmlFree(cur);
1789}
1790
Daniel Veillard652327a2003-09-29 18:02:38 +00001791#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001792/**
1793 * xmlCopyEnumeration:
1794 * @cur: the tree to copy.
1795 *
1796 * Copy an enumeration attribute node (recursive).
1797 *
1798 * Returns the xmlEnumerationPtr just created or NULL in case
1799 * of error.
1800 */
1801xmlEnumerationPtr
1802xmlCopyEnumeration(xmlEnumerationPtr cur) {
1803 xmlEnumerationPtr ret;
1804
1805 if (cur == NULL) return(NULL);
1806 ret = xmlCreateEnumeration((xmlChar *) cur->name);
Gaurav Gupta658b86c2014-08-07 11:19:03 +08001807 if (ret == NULL) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001808
1809 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1810 else ret->next = NULL;
1811
1812 return(ret);
1813}
Daniel Veillard652327a2003-09-29 18:02:38 +00001814#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001815
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001816#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001817/**
1818 * xmlDumpEnumeration:
1819 * @buf: the XML buffer output
1820 * @enum: An enumeration
1821 *
1822 * This will dump the content of the enumeration
1823 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001824static void
Owen Taylor3473f882001-02-23 17:55:21 +00001825xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00001826 if ((buf == NULL) || (cur == NULL))
1827 return;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001828
Owen Taylor3473f882001-02-23 17:55:21 +00001829 xmlBufferWriteCHAR(buf, cur->name);
1830 if (cur->next == NULL)
1831 xmlBufferWriteChar(buf, ")");
1832 else {
1833 xmlBufferWriteChar(buf, " | ");
1834 xmlDumpEnumeration(buf, cur->next);
1835 }
1836}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001837#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001838
Daniel Veillard4432df22003-09-28 18:58:27 +00001839#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001840/**
Owen Taylor3473f882001-02-23 17:55:21 +00001841 * xmlScanIDAttributeDecl:
1842 * @ctxt: the validation context
1843 * @elem: the element name
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001844 * @err: whether to raise errors here
Owen Taylor3473f882001-02-23 17:55:21 +00001845 *
1846 * Verify that the element don't have too many ID attributes
1847 * declared.
1848 *
1849 * Returns the number of ID attributes found.
1850 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001851static int
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001852xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
Owen Taylor3473f882001-02-23 17:55:21 +00001853 xmlAttributePtr cur;
1854 int ret = 0;
1855
1856 if (elem == NULL) return(0);
1857 cur = elem->attributes;
1858 while (cur != NULL) {
1859 if (cur->atype == XML_ATTRIBUTE_ID) {
1860 ret ++;
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001861 if ((ret > 1) && (err))
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001862 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001863 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001864 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001865 }
1866 cur = cur->nexth;
1867 }
1868 return(ret);
1869}
Daniel Veillard4432df22003-09-28 18:58:27 +00001870#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001871
1872/**
1873 * xmlFreeAttribute:
1874 * @elem: An attribute
1875 *
1876 * Deallocate the memory used by an attribute definition
1877 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001878static void
Owen Taylor3473f882001-02-23 17:55:21 +00001879xmlFreeAttribute(xmlAttributePtr attr) {
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001880 xmlDictPtr dict;
1881
Owen Taylor3473f882001-02-23 17:55:21 +00001882 if (attr == NULL) return;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001883 if (attr->doc != NULL)
1884 dict = attr->doc->dict;
1885 else
1886 dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001887 xmlUnlinkNode((xmlNodePtr) attr);
1888 if (attr->tree != NULL)
1889 xmlFreeEnumeration(attr->tree);
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001890 if (dict) {
1891 if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1892 xmlFree((xmlChar *) attr->elem);
1893 if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1894 xmlFree((xmlChar *) attr->name);
1895 if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1896 xmlFree((xmlChar *) attr->prefix);
1897 if ((attr->defaultValue != NULL) &&
1898 (!xmlDictOwns(dict, attr->defaultValue)))
1899 xmlFree((xmlChar *) attr->defaultValue);
1900 } else {
1901 if (attr->elem != NULL)
1902 xmlFree((xmlChar *) attr->elem);
1903 if (attr->name != NULL)
1904 xmlFree((xmlChar *) attr->name);
1905 if (attr->defaultValue != NULL)
1906 xmlFree((xmlChar *) attr->defaultValue);
1907 if (attr->prefix != NULL)
1908 xmlFree((xmlChar *) attr->prefix);
1909 }
Owen Taylor3473f882001-02-23 17:55:21 +00001910 xmlFree(attr);
1911}
1912
1913
1914/**
1915 * xmlAddAttributeDecl:
1916 * @ctxt: the validation context
1917 * @dtd: pointer to the DTD
1918 * @elem: the element name
1919 * @name: the attribute name
1920 * @ns: the attribute namespace prefix
1921 * @type: the attribute type
1922 * @def: the attribute default type
1923 * @defaultValue: the attribute default value
1924 * @tree: if it's an enumeration, the associated list
1925 *
1926 * Register a new attribute declaration
1927 * Note that @tree becomes the ownership of the DTD
1928 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001929 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001930 */
1931xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001932xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001933 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001934 const xmlChar *name, const xmlChar *ns,
1935 xmlAttributeType type, xmlAttributeDefault def,
1936 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1937 xmlAttributePtr ret;
1938 xmlAttributeTablePtr table;
1939 xmlElementPtr elemDef;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001940 xmlDictPtr dict = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001941
1942 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001943 xmlFreeEnumeration(tree);
1944 return(NULL);
1945 }
1946 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001947 xmlFreeEnumeration(tree);
1948 return(NULL);
1949 }
1950 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001951 xmlFreeEnumeration(tree);
1952 return(NULL);
1953 }
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00001954 if (dtd->doc != NULL)
1955 dict = dtd->doc->dict;
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001956
Daniel Veillard4432df22003-09-28 18:58:27 +00001957#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001958 /*
1959 * Check the type and possibly the default value.
1960 */
1961 switch (type) {
1962 case XML_ATTRIBUTE_CDATA:
1963 break;
1964 case XML_ATTRIBUTE_ID:
1965 break;
1966 case XML_ATTRIBUTE_IDREF:
1967 break;
1968 case XML_ATTRIBUTE_IDREFS:
1969 break;
1970 case XML_ATTRIBUTE_ENTITY:
1971 break;
1972 case XML_ATTRIBUTE_ENTITIES:
1973 break;
1974 case XML_ATTRIBUTE_NMTOKEN:
1975 break;
1976 case XML_ATTRIBUTE_NMTOKENS:
1977 break;
1978 case XML_ATTRIBUTE_ENUMERATION:
1979 break;
1980 case XML_ATTRIBUTE_NOTATION:
1981 break;
1982 default:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001983 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001984 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1985 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001986 xmlFreeEnumeration(tree);
1987 return(NULL);
1988 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001989 if ((defaultValue != NULL) &&
Daniel Veillardae0765b2008-07-31 19:54:59 +00001990 (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001991 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1992 "Attribute %s of %s: invalid default value\n",
1993 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00001994 defaultValue = NULL;
Daniel Veillard42595322004-11-08 10:52:06 +00001995 if (ctxt != NULL)
1996 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001997 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001998#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001999
2000 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00002001 * Check first that an attribute defined in the external subset wasn't
2002 * already defined in the internal subset
2003 */
2004 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2005 (dtd->doc->intSubset != NULL) &&
2006 (dtd->doc->intSubset->attributes != NULL)) {
2007 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
Daniel Veillardae0765b2008-07-31 19:54:59 +00002008 if (ret != NULL) {
2009 xmlFreeEnumeration(tree);
Daniel Veillardd85f4f42002-03-25 10:48:46 +00002010 return(NULL);
Daniel Veillardae0765b2008-07-31 19:54:59 +00002011 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00002012 }
2013
2014 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002015 * Create the Attribute table if needed.
2016 */
2017 table = (xmlAttributeTablePtr) dtd->attributes;
2018 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00002019 table = xmlHashCreateDict(0, dict);
Owen Taylor3473f882001-02-23 17:55:21 +00002020 dtd->attributes = (void *) table;
2021 }
2022 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002023 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002024 "xmlAddAttributeDecl: Table creation failed!\n");
Daniel Veillardae0765b2008-07-31 19:54:59 +00002025 xmlFreeEnumeration(tree);
Owen Taylor3473f882001-02-23 17:55:21 +00002026 return(NULL);
2027 }
2028
2029
2030 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2031 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002032 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardae0765b2008-07-31 19:54:59 +00002033 xmlFreeEnumeration(tree);
Owen Taylor3473f882001-02-23 17:55:21 +00002034 return(NULL);
2035 }
2036 memset(ret, 0, sizeof(xmlAttribute));
2037 ret->type = XML_ATTRIBUTE_DECL;
2038
2039 /*
2040 * fill the structure.
2041 */
2042 ret->atype = type;
William M. Brackf810de02005-07-06 22:48:41 +00002043 /*
2044 * doc must be set before possible error causes call
2045 * to xmlFreeAttribute (because it's used to check on
2046 * dict use)
2047 */
2048 ret->doc = dtd->doc;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002049 if (dict) {
2050 ret->name = xmlDictLookup(dict, name, -1);
2051 ret->prefix = xmlDictLookup(dict, ns, -1);
2052 ret->elem = xmlDictLookup(dict, elem, -1);
2053 } else {
2054 ret->name = xmlStrdup(name);
2055 ret->prefix = xmlStrdup(ns);
2056 ret->elem = xmlStrdup(elem);
2057 }
Owen Taylor3473f882001-02-23 17:55:21 +00002058 ret->def = def;
2059 ret->tree = tree;
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002060 if (defaultValue != NULL) {
2061 if (dict)
2062 ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2063 else
2064 ret->defaultValue = xmlStrdup(defaultValue);
2065 }
Owen Taylor3473f882001-02-23 17:55:21 +00002066
2067 /*
2068 * Validity Check:
2069 * Search the DTD for previous declarations of the ATTLIST
2070 */
Daniel Veillardcee2b3a2005-01-25 00:22:52 +00002071 if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002072#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002073 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002074 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002075 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002076 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00002077 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002078 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00002079#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002080 xmlFreeAttribute(ret);
2081 return(NULL);
2082 }
2083
2084 /*
2085 * Validity Check:
2086 * Multiple ID per element
2087 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00002088 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002089 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00002090
Daniel Veillard4432df22003-09-28 18:58:27 +00002091#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002092 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillarddbee0f12005-06-27 13:42:57 +00002093 (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002094 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00002095 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002096 elem, name, NULL);
Daniel Veillard42595322004-11-08 10:52:06 +00002097 if (ctxt != NULL)
2098 ctxt->valid = 0;
Daniel Veillardc7612992002-02-17 22:47:37 +00002099 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002100#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00002101
Daniel Veillard48da9102001-08-07 01:10:10 +00002102 /*
2103 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002104 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00002105 */
2106 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2107 ((ret->prefix != NULL &&
2108 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2109 ret->nexth = elemDef->attributes;
2110 elemDef->attributes = ret;
2111 } else {
2112 xmlAttributePtr tmp = elemDef->attributes;
2113
2114 while ((tmp != NULL) &&
2115 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2116 ((ret->prefix != NULL &&
2117 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2118 if (tmp->nexth == NULL)
2119 break;
2120 tmp = tmp->nexth;
2121 }
2122 if (tmp != NULL) {
2123 ret->nexth = tmp->nexth;
2124 tmp->nexth = ret;
2125 } else {
2126 ret->nexth = elemDef->attributes;
2127 elemDef->attributes = ret;
2128 }
2129 }
Owen Taylor3473f882001-02-23 17:55:21 +00002130 }
2131
2132 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002133 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00002134 */
2135 ret->parent = dtd;
Owen Taylor3473f882001-02-23 17:55:21 +00002136 if (dtd->last == NULL) {
2137 dtd->children = dtd->last = (xmlNodePtr) ret;
2138 } else {
2139 dtd->last->next = (xmlNodePtr) ret;
2140 ret->prev = dtd->last;
2141 dtd->last = (xmlNodePtr) ret;
2142 }
2143 return(ret);
2144}
2145
2146/**
2147 * xmlFreeAttributeTable:
2148 * @table: An attribute table
2149 *
2150 * Deallocate the memory used by an entities hash table.
2151 */
2152void
2153xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2154 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
2155}
2156
Daniel Veillard652327a2003-09-29 18:02:38 +00002157#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002158/**
2159 * xmlCopyAttribute:
2160 * @attr: An attribute
2161 *
2162 * Build a copy of an attribute.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002163 *
Owen Taylor3473f882001-02-23 17:55:21 +00002164 * Returns the new xmlAttributePtr or NULL in case of error.
2165 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002166static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002167xmlCopyAttribute(xmlAttributePtr attr) {
2168 xmlAttributePtr cur;
2169
2170 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2171 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002172 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002173 return(NULL);
2174 }
2175 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00002176 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00002177 cur->atype = attr->atype;
2178 cur->def = attr->def;
2179 cur->tree = xmlCopyEnumeration(attr->tree);
2180 if (attr->elem != NULL)
2181 cur->elem = xmlStrdup(attr->elem);
2182 if (attr->name != NULL)
2183 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002184 if (attr->prefix != NULL)
2185 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002186 if (attr->defaultValue != NULL)
2187 cur->defaultValue = xmlStrdup(attr->defaultValue);
2188 return(cur);
2189}
2190
2191/**
2192 * xmlCopyAttributeTable:
2193 * @table: An attribute table
2194 *
2195 * Build a copy of an attribute table.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002196 *
Owen Taylor3473f882001-02-23 17:55:21 +00002197 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2198 */
2199xmlAttributeTablePtr
2200xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2201 return((xmlAttributeTablePtr) xmlHashCopy(table,
2202 (xmlHashCopier) xmlCopyAttribute));
2203}
Daniel Veillard652327a2003-09-29 18:02:38 +00002204#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002205
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002206#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002207/**
2208 * xmlDumpAttributeDecl:
2209 * @buf: the XML buffer output
2210 * @attr: An attribute declaration
2211 *
2212 * This will dump the content of the attribute declaration as an XML
2213 * DTD definition
2214 */
2215void
2216xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002217 if ((buf == NULL) || (attr == NULL))
2218 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002219 xmlBufferWriteChar(buf, "<!ATTLIST ");
2220 xmlBufferWriteCHAR(buf, attr->elem);
2221 xmlBufferWriteChar(buf, " ");
2222 if (attr->prefix != NULL) {
2223 xmlBufferWriteCHAR(buf, attr->prefix);
2224 xmlBufferWriteChar(buf, ":");
2225 }
2226 xmlBufferWriteCHAR(buf, attr->name);
2227 switch (attr->atype) {
2228 case XML_ATTRIBUTE_CDATA:
2229 xmlBufferWriteChar(buf, " CDATA");
2230 break;
2231 case XML_ATTRIBUTE_ID:
2232 xmlBufferWriteChar(buf, " ID");
2233 break;
2234 case XML_ATTRIBUTE_IDREF:
2235 xmlBufferWriteChar(buf, " IDREF");
2236 break;
2237 case XML_ATTRIBUTE_IDREFS:
2238 xmlBufferWriteChar(buf, " IDREFS");
2239 break;
2240 case XML_ATTRIBUTE_ENTITY:
2241 xmlBufferWriteChar(buf, " ENTITY");
2242 break;
2243 case XML_ATTRIBUTE_ENTITIES:
2244 xmlBufferWriteChar(buf, " ENTITIES");
2245 break;
2246 case XML_ATTRIBUTE_NMTOKEN:
2247 xmlBufferWriteChar(buf, " NMTOKEN");
2248 break;
2249 case XML_ATTRIBUTE_NMTOKENS:
2250 xmlBufferWriteChar(buf, " NMTOKENS");
2251 break;
2252 case XML_ATTRIBUTE_ENUMERATION:
2253 xmlBufferWriteChar(buf, " (");
2254 xmlDumpEnumeration(buf, attr->tree);
2255 break;
2256 case XML_ATTRIBUTE_NOTATION:
2257 xmlBufferWriteChar(buf, " NOTATION (");
2258 xmlDumpEnumeration(buf, attr->tree);
2259 break;
2260 default:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002261 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002262 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2263 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002264 }
2265 switch (attr->def) {
2266 case XML_ATTRIBUTE_NONE:
2267 break;
2268 case XML_ATTRIBUTE_REQUIRED:
2269 xmlBufferWriteChar(buf, " #REQUIRED");
2270 break;
2271 case XML_ATTRIBUTE_IMPLIED:
2272 xmlBufferWriteChar(buf, " #IMPLIED");
2273 break;
2274 case XML_ATTRIBUTE_FIXED:
2275 xmlBufferWriteChar(buf, " #FIXED");
2276 break;
2277 default:
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002278 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002279 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2280 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002281 }
2282 if (attr->defaultValue != NULL) {
2283 xmlBufferWriteChar(buf, " ");
2284 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2285 }
2286 xmlBufferWriteChar(buf, ">\n");
2287}
2288
2289/**
William M. Brack9e660592003-10-20 14:56:06 +00002290 * xmlDumpAttributeDeclScan:
2291 * @attr: An attribute declaration
2292 * @buf: the XML buffer output
2293 *
2294 * This is used with the hash scan function - just reverses arguments
2295 */
2296static void
2297xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2298 xmlDumpAttributeDecl(buf, attr);
2299}
2300
2301/**
Owen Taylor3473f882001-02-23 17:55:21 +00002302 * xmlDumpAttributeTable:
2303 * @buf: the XML buffer output
2304 * @table: An attribute table
2305 *
2306 * This will dump the content of the attribute table as an XML DTD definition
2307 */
2308void
2309xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002310 if ((buf == NULL) || (table == NULL))
2311 return;
William M. Brack9e660592003-10-20 14:56:06 +00002312 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002313}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002314#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002315
2316/************************************************************************
2317 * *
2318 * NOTATIONs *
2319 * *
2320 ************************************************************************/
2321/**
Owen Taylor3473f882001-02-23 17:55:21 +00002322 * xmlFreeNotation:
2323 * @not: A notation
2324 *
2325 * Deallocate the memory used by an notation definition
2326 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002327static void
Owen Taylor3473f882001-02-23 17:55:21 +00002328xmlFreeNotation(xmlNotationPtr nota) {
2329 if (nota == NULL) return;
2330 if (nota->name != NULL)
2331 xmlFree((xmlChar *) nota->name);
2332 if (nota->PublicID != NULL)
2333 xmlFree((xmlChar *) nota->PublicID);
2334 if (nota->SystemID != NULL)
2335 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002336 xmlFree(nota);
2337}
2338
2339
2340/**
2341 * xmlAddNotationDecl:
2342 * @dtd: pointer to the DTD
2343 * @ctxt: the validation context
2344 * @name: the entity name
2345 * @PublicID: the public identifier or NULL
2346 * @SystemID: the system identifier or NULL
2347 *
2348 * Register a new notation declaration
2349 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002350 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002351 */
2352xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002353xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002354 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002355 const xmlChar *PublicID, const xmlChar *SystemID) {
2356 xmlNotationPtr ret;
2357 xmlNotationTablePtr table;
2358
2359 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002360 return(NULL);
2361 }
2362 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002363 return(NULL);
2364 }
2365 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002366 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002367 }
2368
2369 /*
2370 * Create the Notation table if needed.
2371 */
2372 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002373 if (table == NULL) {
2374 xmlDictPtr dict = NULL;
2375 if (dtd->doc != NULL)
2376 dict = dtd->doc->dict;
2377
2378 dtd->notations = table = xmlHashCreateDict(0, dict);
2379 }
Owen Taylor3473f882001-02-23 17:55:21 +00002380 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002381 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002382 "xmlAddNotationDecl: Table creation failed!\n");
2383 return(NULL);
2384 }
2385
2386 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2387 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002388 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002389 return(NULL);
2390 }
2391 memset(ret, 0, sizeof(xmlNotation));
2392
2393 /*
2394 * fill the structure.
2395 */
2396 ret->name = xmlStrdup(name);
2397 if (SystemID != NULL)
2398 ret->SystemID = xmlStrdup(SystemID);
2399 if (PublicID != NULL)
2400 ret->PublicID = xmlStrdup(PublicID);
2401
2402 /*
2403 * Validity Check:
2404 * Check the DTD for previous declarations of the ATTLIST
2405 */
2406 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002407#ifdef LIBXML_VALID_ENABLED
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002408 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002409 "xmlAddNotationDecl: %s already defined\n",
2410 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002411#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002412 xmlFreeNotation(ret);
2413 return(NULL);
2414 }
2415 return(ret);
2416}
2417
2418/**
2419 * xmlFreeNotationTable:
2420 * @table: An notation table
2421 *
2422 * Deallocate the memory used by an entities hash table.
2423 */
2424void
2425xmlFreeNotationTable(xmlNotationTablePtr table) {
2426 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2427}
2428
Daniel Veillard652327a2003-09-29 18:02:38 +00002429#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002430/**
2431 * xmlCopyNotation:
2432 * @nota: A notation
2433 *
2434 * Build a copy of a notation.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002435 *
Owen Taylor3473f882001-02-23 17:55:21 +00002436 * Returns the new xmlNotationPtr or NULL in case of error.
2437 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002438static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002439xmlCopyNotation(xmlNotationPtr nota) {
2440 xmlNotationPtr cur;
2441
2442 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2443 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002444 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002445 return(NULL);
2446 }
2447 if (nota->name != NULL)
2448 cur->name = xmlStrdup(nota->name);
2449 else
2450 cur->name = NULL;
2451 if (nota->PublicID != NULL)
2452 cur->PublicID = xmlStrdup(nota->PublicID);
2453 else
2454 cur->PublicID = NULL;
2455 if (nota->SystemID != NULL)
2456 cur->SystemID = xmlStrdup(nota->SystemID);
2457 else
2458 cur->SystemID = NULL;
2459 return(cur);
2460}
2461
2462/**
2463 * xmlCopyNotationTable:
2464 * @table: A notation table
2465 *
2466 * Build a copy of a notation table.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002467 *
Owen Taylor3473f882001-02-23 17:55:21 +00002468 * Returns the new xmlNotationTablePtr or NULL in case of error.
2469 */
2470xmlNotationTablePtr
2471xmlCopyNotationTable(xmlNotationTablePtr table) {
2472 return((xmlNotationTablePtr) xmlHashCopy(table,
2473 (xmlHashCopier) xmlCopyNotation));
2474}
Daniel Veillard652327a2003-09-29 18:02:38 +00002475#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002476
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002477#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002478/**
2479 * xmlDumpNotationDecl:
2480 * @buf: the XML buffer output
2481 * @nota: A notation declaration
2482 *
2483 * This will dump the content the notation declaration as an XML DTD definition
2484 */
2485void
2486xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002487 if ((buf == NULL) || (nota == NULL))
2488 return;
Owen Taylor3473f882001-02-23 17:55:21 +00002489 xmlBufferWriteChar(buf, "<!NOTATION ");
2490 xmlBufferWriteCHAR(buf, nota->name);
2491 if (nota->PublicID != NULL) {
2492 xmlBufferWriteChar(buf, " PUBLIC ");
2493 xmlBufferWriteQuotedString(buf, nota->PublicID);
2494 if (nota->SystemID != NULL) {
2495 xmlBufferWriteChar(buf, " ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002496 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002497 }
2498 } else {
2499 xmlBufferWriteChar(buf, " SYSTEM ");
Daniel Veillard41c4a752004-09-08 20:55:38 +00002500 xmlBufferWriteQuotedString(buf, nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002501 }
2502 xmlBufferWriteChar(buf, " >\n");
2503}
2504
2505/**
William M. Brack9e660592003-10-20 14:56:06 +00002506 * xmlDumpNotationDeclScan:
2507 * @nota: A notation declaration
2508 * @buf: the XML buffer output
2509 *
2510 * This is called with the hash scan function, and just reverses args
2511 */
2512static void
2513xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2514 xmlDumpNotationDecl(buf, nota);
2515}
2516
2517/**
Owen Taylor3473f882001-02-23 17:55:21 +00002518 * xmlDumpNotationTable:
2519 * @buf: the XML buffer output
2520 * @table: A notation table
2521 *
2522 * This will dump the content of the notation table as an XML DTD definition
2523 */
2524void
2525xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillardce682bc2004-11-05 17:22:25 +00002526 if ((buf == NULL) || (table == NULL))
2527 return;
William M. Brack9e660592003-10-20 14:56:06 +00002528 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002529}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002530#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002531
2532/************************************************************************
2533 * *
2534 * IDs *
2535 * *
2536 ************************************************************************/
2537/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002538 * DICT_FREE:
2539 * @str: a string
2540 *
Jan Pokornýbb654fe2016-04-13 16:56:07 +02002541 * Free a string if it is not owned by the "dict" dictionary in the
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002542 * current scope
2543 */
2544#define DICT_FREE(str) \
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002545 if ((str) && ((!dict) || \
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002546 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2547 xmlFree((char *)(str));
2548
2549/**
Owen Taylor3473f882001-02-23 17:55:21 +00002550 * xmlFreeID:
2551 * @not: A id
2552 *
2553 * Deallocate the memory used by an id definition
2554 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002555static void
Owen Taylor3473f882001-02-23 17:55:21 +00002556xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002557 xmlDictPtr dict = NULL;
2558
Owen Taylor3473f882001-02-23 17:55:21 +00002559 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002560
2561 if (id->doc != NULL)
2562 dict = id->doc->dict;
2563
Owen Taylor3473f882001-02-23 17:55:21 +00002564 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002565 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002566 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002567 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002568 xmlFree(id);
2569}
2570
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002571
Owen Taylor3473f882001-02-23 17:55:21 +00002572/**
2573 * xmlAddID:
2574 * @ctxt: the validation context
2575 * @doc: pointer to the document
2576 * @value: the value name
2577 * @attr: the attribute holding the ID
2578 *
2579 * Register a new id declaration
2580 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002581 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002582 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002583xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002584xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2585 xmlAttrPtr attr) {
2586 xmlIDPtr ret;
2587 xmlIDTablePtr table;
2588
2589 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002590 return(NULL);
2591 }
2592 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002593 return(NULL);
2594 }
2595 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002596 return(NULL);
2597 }
2598
2599 /*
2600 * Create the ID table if needed.
2601 */
2602 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002603 if (table == NULL) {
2604 doc->ids = table = xmlHashCreateDict(0, doc->dict);
2605 }
Owen Taylor3473f882001-02-23 17:55:21 +00002606 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002607 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002608 "xmlAddID: Table creation failed!\n");
2609 return(NULL);
2610 }
2611
2612 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2613 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002614 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002615 return(NULL);
2616 }
2617
2618 /*
2619 * fill the structure.
2620 */
2621 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002622 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002623 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2624 /*
2625 * Operating in streaming mode, attr is gonna disapear
2626 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002627 if (doc->dict != NULL)
2628 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2629 else
2630 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002631 ret->attr = NULL;
2632 } else {
2633 ret->attr = attr;
2634 ret->name = NULL;
2635 }
2636 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002637
2638 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002639#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002640 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002641 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002642 */
Daniel Veillardef709ce2015-09-10 19:41:41 +08002643 if (ctxt != NULL) {
2644 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2645 "ID %s already defined\n", value, NULL, NULL);
2646 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002647#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002648 xmlFreeID(ret);
2649 return(NULL);
2650 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002651 if (attr != NULL)
2652 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002653 return(ret);
2654}
2655
2656/**
2657 * xmlFreeIDTable:
2658 * @table: An id table
2659 *
2660 * Deallocate the memory used by an ID hash table.
2661 */
2662void
2663xmlFreeIDTable(xmlIDTablePtr table) {
2664 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2665}
2666
2667/**
2668 * xmlIsID:
2669 * @doc: the document
2670 * @elem: the element carrying the attribute
2671 * @attr: the attribute
2672 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002673 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002674 * then this is done if DTD loading has been requested. In the case
2675 * of HTML documents parsed with the HTML parser, then ID detection is
2676 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002677 *
2678 * Returns 0 or 1 depending on the lookup result
2679 */
2680int
2681xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard54f9a4f2005-09-03 13:28:24 +00002682 if ((attr == NULL) || (attr->name == NULL)) return(0);
2683 if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2684 (!strcmp((char *) attr->name, "id")) &&
2685 (!strcmp((char *) attr->ns->prefix, "xml")))
2686 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002687 if (doc == NULL) return(0);
Daniel Veillardf3c06692009-10-16 16:47:58 +02002688 if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
2689 (doc->type != XML_HTML_DOCUMENT_NODE)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002690 return(0);
2691 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Rob Richards04bffc02006-03-03 16:44:37 +00002692 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2693 ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
Daniel Veillard38431c32007-06-12 16:20:09 +00002694 ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
Owen Taylor3473f882001-02-23 17:55:21 +00002695 return(1);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002696 return(0);
Daniel Veillard379a3b72005-08-12 10:18:14 +00002697 } else if (elem == NULL) {
2698 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002699 } else {
Daniel Veillard465a0002005-08-22 12:07:04 +00002700 xmlAttributePtr attrDecl = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002701
Daniel Veillard379a3b72005-08-12 10:18:14 +00002702 xmlChar felem[50], fattr[50];
2703 xmlChar *fullelemname, *fullattrname;
2704
2705 fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2706 xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2707 (xmlChar *)elem->name;
2708
2709 fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2710 xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2711 (xmlChar *)attr->name;
2712
2713 if (fullelemname != NULL && fullattrname != NULL) {
2714 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2715 fullattrname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002716 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillard379a3b72005-08-12 10:18:14 +00002717 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2718 fullattrname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002719 }
Owen Taylor3473f882001-02-23 17:55:21 +00002720
Daniel Veillard379a3b72005-08-12 10:18:14 +00002721 if ((fullattrname != fattr) && (fullattrname != attr->name))
2722 xmlFree(fullattrname);
2723 if ((fullelemname != felem) && (fullelemname != elem->name))
2724 xmlFree(fullelemname);
2725
Owen Taylor3473f882001-02-23 17:55:21 +00002726 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2727 return(1);
2728 }
2729 return(0);
2730}
2731
2732/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002733 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002734 * @doc: the document
2735 * @attr: the attribute
2736 *
2737 * Remove the given attribute from the ID table maintained internally.
2738 *
2739 * Returns -1 if the lookup failed and 0 otherwise
2740 */
2741int
2742xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002743 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002744 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002745 xmlChar *ID;
2746
2747 if (doc == NULL) return(-1);
2748 if (attr == NULL) return(-1);
Denis Pauk01461792013-08-06 09:55:55 +03002749
Owen Taylor3473f882001-02-23 17:55:21 +00002750 table = (xmlIDTablePtr) doc->ids;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002751 if (table == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002752 return(-1);
2753
Owen Taylor3473f882001-02-23 17:55:21 +00002754 ID = xmlNodeListGetString(doc, attr->children, 1);
2755 if (ID == NULL)
Denis Pauk01461792013-08-06 09:55:55 +03002756 return(-1);
2757
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002758 id = xmlHashLookup(table, ID);
2759 if (id == NULL || id->attr != attr) {
Denis Pauk01461792013-08-06 09:55:55 +03002760 xmlFree(ID);
2761 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002762 }
Denis Pauk01461792013-08-06 09:55:55 +03002763
Daniel Veillard91b955c2004-12-10 10:26:42 +00002764 xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID);
Owen Taylor3473f882001-02-23 17:55:21 +00002765 xmlFree(ID);
Denis Pauk01461792013-08-06 09:55:55 +03002766 attr->atype = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002767 return(0);
2768}
2769
2770/**
2771 * xmlGetID:
2772 * @doc: pointer to the document
2773 * @ID: the ID value
2774 *
2775 * Search the attribute declaring the given ID
2776 *
2777 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2778 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002779xmlAttrPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002780xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2781 xmlIDTablePtr table;
2782 xmlIDPtr id;
2783
2784 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002785 return(NULL);
2786 }
2787
2788 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002789 return(NULL);
2790 }
2791
2792 table = (xmlIDTablePtr) doc->ids;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002793 if (table == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002794 return(NULL);
2795
2796 id = xmlHashLookup(table, ID);
2797 if (id == NULL)
2798 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002799 if (id->attr == NULL) {
2800 /*
2801 * We are operating on a stream, return a well known reference
2802 * since the attribute node doesn't exist anymore
2803 */
2804 return((xmlAttrPtr) doc);
2805 }
Owen Taylor3473f882001-02-23 17:55:21 +00002806 return(id->attr);
2807}
2808
2809/************************************************************************
2810 * *
2811 * Refs *
2812 * *
2813 ************************************************************************/
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002814typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002815{
2816 xmlListPtr l;
2817 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002818} xmlRemoveMemo;
2819
2820typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2821
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002822typedef struct xmlValidateMemo_t
Daniel Veillard8730c562001-02-26 10:49:57 +00002823{
2824 xmlValidCtxtPtr ctxt;
2825 const xmlChar *name;
2826} xmlValidateMemo;
2827
2828typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002829
2830/**
Owen Taylor3473f882001-02-23 17:55:21 +00002831 * xmlFreeRef:
2832 * @lk: A list link
2833 *
2834 * Deallocate the memory used by a ref definition
2835 */
2836static void
2837xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002838 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2839 if (ref == NULL) return;
2840 if (ref->value != NULL)
2841 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002842 if (ref->name != NULL)
2843 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002844 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002845}
2846
2847/**
2848 * xmlFreeRefList:
2849 * @list_ref: A list of references.
2850 *
2851 * Deallocate the memory used by a list of references
2852 */
2853static void
2854xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002855 if (list_ref == NULL) return;
2856 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002857}
2858
2859/**
2860 * xmlWalkRemoveRef:
2861 * @data: Contents of current link
2862 * @user: Value supplied by the user
2863 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002864 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002865 */
2866static int
2867xmlWalkRemoveRef(const void *data, const void *user)
2868{
Daniel Veillard37721922001-05-04 15:21:12 +00002869 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2870 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2871 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002872
Daniel Veillard37721922001-05-04 15:21:12 +00002873 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2874 xmlListRemoveFirst(ref_list, (void *)data);
2875 return 0;
2876 }
2877 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002878}
2879
2880/**
Daniel Veillard770075b2004-02-25 10:44:30 +00002881 * xmlDummyCompare
2882 * @data0: Value supplied by the user
2883 * @data1: Value supplied by the user
2884 *
2885 * Do nothing, return 0. Used to create unordered lists.
2886 */
2887static int
Daniel Veillardf54cd532004-02-25 11:52:31 +00002888xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2889 const void *data1 ATTRIBUTE_UNUSED)
Daniel Veillard770075b2004-02-25 10:44:30 +00002890{
2891 return (0);
2892}
2893
2894/**
Owen Taylor3473f882001-02-23 17:55:21 +00002895 * xmlAddRef:
2896 * @ctxt: the validation context
2897 * @doc: pointer to the document
2898 * @value: the value name
2899 * @attr: the attribute holding the Ref
2900 *
2901 * Register a new ref declaration
2902 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002903 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002904 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08002905xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002906xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002907 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002908 xmlRefPtr ret;
2909 xmlRefTablePtr table;
2910 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002911
Daniel Veillard37721922001-05-04 15:21:12 +00002912 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002913 return(NULL);
2914 }
2915 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002916 return(NULL);
2917 }
2918 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002919 return(NULL);
2920 }
Owen Taylor3473f882001-02-23 17:55:21 +00002921
Daniel Veillard37721922001-05-04 15:21:12 +00002922 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002923 * Create the Ref table if needed.
2924 */
Daniel Veillard37721922001-05-04 15:21:12 +00002925 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard316a5c32005-01-23 22:56:39 +00002926 if (table == NULL) {
2927 doc->refs = table = xmlHashCreateDict(0, doc->dict);
2928 }
Daniel Veillard37721922001-05-04 15:21:12 +00002929 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002930 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002931 "xmlAddRef: Table creation failed!\n");
2932 return(NULL);
2933 }
Owen Taylor3473f882001-02-23 17:55:21 +00002934
Daniel Veillard37721922001-05-04 15:21:12 +00002935 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2936 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002937 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002938 return(NULL);
2939 }
Owen Taylor3473f882001-02-23 17:55:21 +00002940
Daniel Veillard37721922001-05-04 15:21:12 +00002941 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002942 * fill the structure.
2943 */
Daniel Veillard37721922001-05-04 15:21:12 +00002944 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002945 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2946 /*
2947 * Operating in streaming mode, attr is gonna disapear
2948 */
2949 ret->name = xmlStrdup(attr->name);
2950 ret->attr = NULL;
2951 } else {
2952 ret->name = NULL;
2953 ret->attr = attr;
2954 }
2955 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002956
Daniel Veillard37721922001-05-04 15:21:12 +00002957 /* To add a reference :-
2958 * References are maintained as a list of references,
2959 * Lookup the entry, if no entry create new nodelist
2960 * Add the owning node to the NodeList
2961 * Return the ref
2962 */
Owen Taylor3473f882001-02-23 17:55:21 +00002963
Daniel Veillard37721922001-05-04 15:21:12 +00002964 if (NULL == (ref_list = xmlHashLookup(table, value))) {
Daniel Veillard770075b2004-02-25 10:44:30 +00002965 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002966 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2967 "xmlAddRef: Reference list creation failed!\n",
2968 NULL);
Daniel Veillardf6cf57a2007-05-09 23:53:30 +00002969 goto failed;
Daniel Veillard37721922001-05-04 15:21:12 +00002970 }
2971 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2972 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002973 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2974 "xmlAddRef: Reference list insertion failed!\n",
2975 NULL);
Daniel Veillardf6cf57a2007-05-09 23:53:30 +00002976 goto failed;
Daniel Veillard37721922001-05-04 15:21:12 +00002977 }
2978 }
Daniel Veillardf6cf57a2007-05-09 23:53:30 +00002979 if (xmlListAppend(ref_list, ret) != 0) {
2980 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2981 "xmlAddRef: Reference list insertion failed!\n",
2982 NULL);
2983 goto failed;
2984 }
Daniel Veillard37721922001-05-04 15:21:12 +00002985 return(ret);
Daniel Veillardf6cf57a2007-05-09 23:53:30 +00002986failed:
2987 if (ret != NULL) {
2988 if (ret->value != NULL)
2989 xmlFree((char *)ret->value);
2990 if (ret->name != NULL)
2991 xmlFree((char *)ret->name);
2992 xmlFree(ret);
2993 }
2994 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002995}
2996
2997/**
2998 * xmlFreeRefTable:
2999 * @table: An ref table
3000 *
3001 * Deallocate the memory used by an Ref hash table.
3002 */
3003void
3004xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00003005 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00003006}
3007
3008/**
3009 * xmlIsRef:
3010 * @doc: the document
3011 * @elem: the element carrying the attribute
3012 * @attr: the attribute
3013 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003014 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00003015 * then this is simple, otherwise we use an heuristic: name Ref (upper
3016 * or lowercase).
3017 *
3018 * Returns 0 or 1 depending on the lookup result
3019 */
3020int
3021xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillardce244ad2004-11-05 10:03:46 +00003022 if (attr == NULL)
3023 return(0);
3024 if (doc == NULL) {
3025 doc = attr->doc;
3026 if (doc == NULL) return(0);
3027 }
3028
Daniel Veillard37721922001-05-04 15:21:12 +00003029 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3030 return(0);
3031 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3032 /* TODO @@@ */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003033 return(0);
Daniel Veillard37721922001-05-04 15:21:12 +00003034 } else {
3035 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00003036
Daniel Veillardce244ad2004-11-05 10:03:46 +00003037 if (elem == NULL) return(0);
Daniel Veillard37721922001-05-04 15:21:12 +00003038 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3039 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3040 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3041 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00003042
Daniel Veillard37721922001-05-04 15:21:12 +00003043 if ((attrDecl != NULL) &&
3044 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3045 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3046 return(1);
3047 }
3048 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003049}
3050
3051/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003052 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00003053 * @doc: the document
3054 * @attr: the attribute
3055 *
3056 * Remove the given attribute from the Ref table maintained internally.
3057 *
3058 * Returns -1 if the lookup failed and 0 otherwise
3059 */
3060int
3061xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00003062 xmlListPtr ref_list;
3063 xmlRefTablePtr table;
3064 xmlChar *ID;
3065 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00003066
Daniel Veillard37721922001-05-04 15:21:12 +00003067 if (doc == NULL) return(-1);
3068 if (attr == NULL) return(-1);
Denis Pauk01461792013-08-06 09:55:55 +03003069
Daniel Veillard37721922001-05-04 15:21:12 +00003070 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003071 if (table == NULL)
Daniel Veillard37721922001-05-04 15:21:12 +00003072 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003073
Daniel Veillard37721922001-05-04 15:21:12 +00003074 ID = xmlNodeListGetString(doc, attr->children, 1);
3075 if (ID == NULL)
3076 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003077
Denis Pauk01461792013-08-06 09:55:55 +03003078 ref_list = xmlHashLookup(table, ID);
Daniel Veillard37721922001-05-04 15:21:12 +00003079 if(ref_list == NULL) {
3080 xmlFree(ID);
3081 return (-1);
3082 }
Denis Pauk01461792013-08-06 09:55:55 +03003083
Daniel Veillard37721922001-05-04 15:21:12 +00003084 /* At this point, ref_list refers to a list of references which
3085 * have the same key as the supplied attr. Our list of references
3086 * is ordered by reference address and we don't have that information
3087 * here to use when removing. We'll have to walk the list and
3088 * check for a matching attribute, when we find one stop the walk
3089 * and remove the entry.
3090 * The list is ordered by reference, so that means we don't have the
3091 * key. Passing the list and the reference to the walker means we
3092 * will have enough data to be able to remove the entry.
3093 */
3094 target.l = ref_list;
3095 target.ap = attr;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003096
Daniel Veillard37721922001-05-04 15:21:12 +00003097 /* Remove the supplied attr from our list */
3098 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00003099
Daniel Veillard37721922001-05-04 15:21:12 +00003100 /*If the list is empty then remove the list entry in the hash */
3101 if (xmlListEmpty(ref_list))
3102 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
3103 xmlFreeRefList);
3104 xmlFree(ID);
3105 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003106}
3107
3108/**
3109 * xmlGetRefs:
3110 * @doc: pointer to the document
3111 * @ID: the ID value
3112 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003113 * Find the set of references for the supplied ID.
Owen Taylor3473f882001-02-23 17:55:21 +00003114 *
3115 * Returns NULL if not found, otherwise node set for the ID.
3116 */
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003117xmlListPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003118xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00003119 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00003120
Daniel Veillard37721922001-05-04 15:21:12 +00003121 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003122 return(NULL);
3123 }
Owen Taylor3473f882001-02-23 17:55:21 +00003124
Daniel Veillard37721922001-05-04 15:21:12 +00003125 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00003126 return(NULL);
3127 }
Owen Taylor3473f882001-02-23 17:55:21 +00003128
Daniel Veillard37721922001-05-04 15:21:12 +00003129 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003130 if (table == NULL)
Daniel Veillard37721922001-05-04 15:21:12 +00003131 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003132
Daniel Veillard37721922001-05-04 15:21:12 +00003133 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00003134}
3135
3136/************************************************************************
3137 * *
3138 * Routines for validity checking *
3139 * *
3140 ************************************************************************/
3141
3142/**
3143 * xmlGetDtdElementDesc:
3144 * @dtd: a pointer to the DtD to search
3145 * @name: the element name
3146 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003147 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003148 *
3149 * returns the xmlElementPtr if found or NULL
3150 */
3151
3152xmlElementPtr
3153xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3154 xmlElementTablePtr table;
3155 xmlElementPtr cur;
3156 xmlChar *uqname = NULL, *prefix = NULL;
3157
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00003158 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003159 if (dtd->elements == NULL)
3160 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003161 table = (xmlElementTablePtr) dtd->elements;
3162
3163 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003164 if (uqname != NULL)
3165 name = uqname;
3166 cur = xmlHashLookup2(table, name, prefix);
3167 if (prefix != NULL) xmlFree(prefix);
3168 if (uqname != NULL) xmlFree(uqname);
3169 return(cur);
3170}
3171/**
3172 * xmlGetDtdElementDesc2:
3173 * @dtd: a pointer to the DtD to search
3174 * @name: the element name
3175 * @create: create an empty description if not found
3176 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003177 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00003178 *
3179 * returns the xmlElementPtr if found or NULL
3180 */
3181
Daniel Veillard86fd5a72001-12-13 14:55:21 +00003182static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00003183xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3184 xmlElementTablePtr table;
3185 xmlElementPtr cur;
3186 xmlChar *uqname = NULL, *prefix = NULL;
3187
3188 if (dtd == NULL) return(NULL);
3189 if (dtd->elements == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003190 xmlDictPtr dict = NULL;
3191
3192 if (dtd->doc != NULL)
3193 dict = dtd->doc->dict;
3194
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003195 if (!create)
Daniel Veillarda10efa82001-04-18 13:09:01 +00003196 return(NULL);
3197 /*
3198 * Create the Element table if needed.
3199 */
3200 table = (xmlElementTablePtr) dtd->elements;
3201 if (table == NULL) {
Daniel Veillard316a5c32005-01-23 22:56:39 +00003202 table = xmlHashCreateDict(0, dict);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003203 dtd->elements = (void *) table;
3204 }
3205 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003206 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003207 return(NULL);
3208 }
3209 }
3210 table = (xmlElementTablePtr) dtd->elements;
3211
3212 uqname = xmlSplitQName2(name, &prefix);
3213 if (uqname != NULL)
3214 name = uqname;
3215 cur = xmlHashLookup2(table, name, prefix);
3216 if ((cur == NULL) && (create)) {
3217 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3218 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003219 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003220 return(NULL);
3221 }
3222 memset(cur, 0, sizeof(xmlElement));
3223 cur->type = XML_ELEMENT_DECL;
3224
3225 /*
3226 * fill the structure.
3227 */
3228 cur->name = xmlStrdup(name);
3229 cur->prefix = xmlStrdup(prefix);
3230 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3231
3232 xmlHashAddEntry2(table, name, prefix, cur);
3233 }
3234 if (prefix != NULL) xmlFree(prefix);
3235 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003236 return(cur);
3237}
3238
3239/**
3240 * xmlGetDtdQElementDesc:
3241 * @dtd: a pointer to the DtD to search
3242 * @name: the element name
3243 * @prefix: the element namespace prefix
3244 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003245 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003246 *
3247 * returns the xmlElementPtr if found or NULL
3248 */
3249
Daniel Veillard48da9102001-08-07 01:10:10 +00003250xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003251xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3252 const xmlChar *prefix) {
3253 xmlElementTablePtr table;
3254
3255 if (dtd == NULL) return(NULL);
3256 if (dtd->elements == NULL) return(NULL);
3257 table = (xmlElementTablePtr) dtd->elements;
3258
3259 return(xmlHashLookup2(table, name, prefix));
3260}
3261
3262/**
3263 * xmlGetDtdAttrDesc:
3264 * @dtd: a pointer to the DtD to search
3265 * @elem: the element name
3266 * @name: the attribute name
3267 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003268 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003269 * this element.
3270 *
3271 * returns the xmlAttributePtr if found or NULL
3272 */
3273
3274xmlAttributePtr
3275xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3276 xmlAttributeTablePtr table;
3277 xmlAttributePtr cur;
3278 xmlChar *uqname = NULL, *prefix = NULL;
3279
3280 if (dtd == NULL) return(NULL);
3281 if (dtd->attributes == NULL) return(NULL);
3282
3283 table = (xmlAttributeTablePtr) dtd->attributes;
3284 if (table == NULL)
3285 return(NULL);
3286
3287 uqname = xmlSplitQName2(name, &prefix);
3288
3289 if (uqname != NULL) {
3290 cur = xmlHashLookup3(table, uqname, prefix, elem);
3291 if (prefix != NULL) xmlFree(prefix);
3292 if (uqname != NULL) xmlFree(uqname);
3293 } else
3294 cur = xmlHashLookup3(table, name, NULL, elem);
3295 return(cur);
3296}
3297
3298/**
3299 * xmlGetDtdQAttrDesc:
3300 * @dtd: a pointer to the DtD to search
3301 * @elem: the element name
3302 * @name: the attribute name
3303 * @prefix: the attribute namespace prefix
3304 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003305 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003306 * this element.
3307 *
3308 * returns the xmlAttributePtr if found or NULL
3309 */
3310
Daniel Veillard48da9102001-08-07 01:10:10 +00003311xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003312xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3313 const xmlChar *prefix) {
3314 xmlAttributeTablePtr table;
3315
3316 if (dtd == NULL) return(NULL);
3317 if (dtd->attributes == NULL) return(NULL);
3318 table = (xmlAttributeTablePtr) dtd->attributes;
3319
3320 return(xmlHashLookup3(table, name, prefix, elem));
3321}
3322
3323/**
3324 * xmlGetDtdNotationDesc:
3325 * @dtd: a pointer to the DtD to search
3326 * @name: the notation name
3327 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003328 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003329 *
3330 * returns the xmlNotationPtr if found or NULL
3331 */
3332
3333xmlNotationPtr
3334xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3335 xmlNotationTablePtr table;
3336
3337 if (dtd == NULL) return(NULL);
3338 if (dtd->notations == NULL) return(NULL);
3339 table = (xmlNotationTablePtr) dtd->notations;
3340
3341 return(xmlHashLookup(table, name));
3342}
3343
Daniel Veillardf54cd532004-02-25 11:52:31 +00003344#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Owen Taylor3473f882001-02-23 17:55:21 +00003345/**
3346 * xmlValidateNotationUse:
3347 * @ctxt: the validation context
3348 * @doc: the document
3349 * @notationName: the notation name to check
3350 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003351 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003352 * - [ VC: Notation Declared ]
3353 *
3354 * returns 1 if valid or 0 otherwise
3355 */
3356
3357int
3358xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3359 const xmlChar *notationName) {
3360 xmlNotationPtr notaDecl;
Daniel Veillardeab3ac92009-08-12 10:39:29 +02003361 if ((doc == NULL) || (doc->intSubset == NULL) ||
3362 (notationName == NULL)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003363
3364 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3365 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3366 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3367
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003368 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003369 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3370 "NOTATION %s is not declared\n",
3371 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003372 return(0);
3373 }
3374 return(1);
3375}
Daniel Veillardf54cd532004-02-25 11:52:31 +00003376#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003377
3378/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003379 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003380 * @doc: the document
3381 * @name: the element name
3382 *
3383 * Search in the DtDs whether an element accept Mixed content (or ANY)
3384 * basically if it is supposed to accept text childs
3385 *
3386 * returns 0 if no, 1 if yes, and -1 if no element description is available
3387 */
3388
3389int
3390xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3391 xmlElementPtr elemDecl;
3392
3393 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3394
3395 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3396 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3397 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3398 if (elemDecl == NULL) return(-1);
3399 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003400 case XML_ELEMENT_TYPE_UNDEFINED:
3401 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003402 case XML_ELEMENT_TYPE_ELEMENT:
3403 return(0);
3404 case XML_ELEMENT_TYPE_EMPTY:
3405 /*
3406 * return 1 for EMPTY since we want VC error to pop up
3407 * on <empty> </empty> for example
3408 */
3409 case XML_ELEMENT_TYPE_ANY:
3410 case XML_ELEMENT_TYPE_MIXED:
3411 return(1);
3412 }
3413 return(1);
3414}
3415
Daniel Veillard4432df22003-09-28 18:58:27 +00003416#ifdef LIBXML_VALID_ENABLED
Daniel Veillardae0765b2008-07-31 19:54:59 +00003417
3418static int
3419xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3420 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3421 /*
3422 * Use the new checks of production [4] [4a] amd [5] of the
3423 * Update 5 of XML-1.0
3424 */
3425 if (((c >= 'a') && (c <= 'z')) ||
3426 ((c >= 'A') && (c <= 'Z')) ||
3427 (c == '_') || (c == ':') ||
3428 ((c >= 0xC0) && (c <= 0xD6)) ||
3429 ((c >= 0xD8) && (c <= 0xF6)) ||
3430 ((c >= 0xF8) && (c <= 0x2FF)) ||
3431 ((c >= 0x370) && (c <= 0x37D)) ||
3432 ((c >= 0x37F) && (c <= 0x1FFF)) ||
3433 ((c >= 0x200C) && (c <= 0x200D)) ||
3434 ((c >= 0x2070) && (c <= 0x218F)) ||
3435 ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3436 ((c >= 0x3001) && (c <= 0xD7FF)) ||
3437 ((c >= 0xF900) && (c <= 0xFDCF)) ||
3438 ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3439 ((c >= 0x10000) && (c <= 0xEFFFF)))
3440 return(1);
3441 } else {
3442 if (IS_LETTER(c) || (c == '_') || (c == ':'))
3443 return(1);
3444 }
3445 return(0);
3446}
3447
3448static int
3449xmlIsDocNameChar(xmlDocPtr doc, int c) {
3450 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3451 /*
3452 * Use the new checks of production [4] [4a] amd [5] of the
3453 * Update 5 of XML-1.0
3454 */
3455 if (((c >= 'a') && (c <= 'z')) ||
3456 ((c >= 'A') && (c <= 'Z')) ||
3457 ((c >= '0') && (c <= '9')) || /* !start */
3458 (c == '_') || (c == ':') ||
3459 (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3460 ((c >= 0xC0) && (c <= 0xD6)) ||
3461 ((c >= 0xD8) && (c <= 0xF6)) ||
3462 ((c >= 0xF8) && (c <= 0x2FF)) ||
3463 ((c >= 0x300) && (c <= 0x36F)) || /* !start */
3464 ((c >= 0x370) && (c <= 0x37D)) ||
3465 ((c >= 0x37F) && (c <= 0x1FFF)) ||
3466 ((c >= 0x200C) && (c <= 0x200D)) ||
3467 ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3468 ((c >= 0x2070) && (c <= 0x218F)) ||
3469 ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3470 ((c >= 0x3001) && (c <= 0xD7FF)) ||
3471 ((c >= 0xF900) && (c <= 0xFDCF)) ||
3472 ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3473 ((c >= 0x10000) && (c <= 0xEFFFF)))
3474 return(1);
3475 } else {
3476 if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3477 (c == '.') || (c == '-') ||
3478 (c == '_') || (c == ':') ||
3479 (IS_COMBINING(c)) ||
3480 (IS_EXTENDER(c)))
3481 return(1);
3482 }
3483 return(0);
3484}
3485
3486/**
3487 * xmlValidateNameValue:
3488 * @doc: pointer to the document or NULL
3489 * @value: an Name value
3490 *
3491 * Validate that the given value match Name production
3492 *
3493 * returns 1 if valid or 0 otherwise
3494 */
3495
3496static int
3497xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3498 const xmlChar *cur;
3499 int val, len;
3500
3501 if (value == NULL) return(0);
3502 cur = value;
3503 val = xmlStringCurrentChar(NULL, cur, &len);
3504 cur += len;
3505 if (!xmlIsDocNameStartChar(doc, val))
3506 return(0);
3507
3508 val = xmlStringCurrentChar(NULL, cur, &len);
3509 cur += len;
3510 while (xmlIsDocNameChar(doc, val)) {
3511 val = xmlStringCurrentChar(NULL, cur, &len);
3512 cur += len;
3513 }
3514
3515 if (val != 0) return(0);
3516
3517 return(1);
3518}
3519
Owen Taylor3473f882001-02-23 17:55:21 +00003520/**
3521 * xmlValidateNameValue:
3522 * @value: an Name value
3523 *
3524 * Validate that the given value match Name production
3525 *
3526 * returns 1 if valid or 0 otherwise
3527 */
3528
Daniel Veillard9b731d72002-04-14 12:56:08 +00003529int
Owen Taylor3473f882001-02-23 17:55:21 +00003530xmlValidateNameValue(const xmlChar *value) {
Daniel Veillardae0765b2008-07-31 19:54:59 +00003531 return(xmlValidateNameValueInternal(NULL, value));
3532}
3533
3534/**
3535 * xmlValidateNamesValueInternal:
3536 * @doc: pointer to the document or NULL
3537 * @value: an Names value
3538 *
3539 * Validate that the given value match Names production
3540 *
3541 * returns 1 if valid or 0 otherwise
3542 */
3543
3544static int
3545xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00003546 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003547 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003548
3549 if (value == NULL) return(0);
3550 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003551 val = xmlStringCurrentChar(NULL, cur, &len);
3552 cur += len;
Daniel Veillardae0765b2008-07-31 19:54:59 +00003553
3554 if (!xmlIsDocNameStartChar(doc, val))
Owen Taylor3473f882001-02-23 17:55:21 +00003555 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003556
Daniel Veillardd8224e02002-01-13 15:43:22 +00003557 val = xmlStringCurrentChar(NULL, cur, &len);
3558 cur += len;
Daniel Veillardae0765b2008-07-31 19:54:59 +00003559 while (xmlIsDocNameChar(doc, val)) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003560 val = xmlStringCurrentChar(NULL, cur, &len);
3561 cur += len;
3562 }
Owen Taylor3473f882001-02-23 17:55:21 +00003563
Daniel Veillardae0765b2008-07-31 19:54:59 +00003564 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3565 while (val == 0x20) {
3566 while (val == 0x20) {
3567 val = xmlStringCurrentChar(NULL, cur, &len);
3568 cur += len;
3569 }
3570
3571 if (!xmlIsDocNameStartChar(doc, val))
3572 return(0);
3573
3574 val = xmlStringCurrentChar(NULL, cur, &len);
3575 cur += len;
3576
3577 while (xmlIsDocNameChar(doc, val)) {
3578 val = xmlStringCurrentChar(NULL, cur, &len);
3579 cur += len;
3580 }
3581 }
3582
Daniel Veillardd8224e02002-01-13 15:43:22 +00003583 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003584
3585 return(1);
3586}
3587
3588/**
3589 * xmlValidateNamesValue:
3590 * @value: an Names value
3591 *
3592 * Validate that the given value match Names production
3593 *
3594 * returns 1 if valid or 0 otherwise
3595 */
3596
Daniel Veillard9b731d72002-04-14 12:56:08 +00003597int
Owen Taylor3473f882001-02-23 17:55:21 +00003598xmlValidateNamesValue(const xmlChar *value) {
Daniel Veillardae0765b2008-07-31 19:54:59 +00003599 return(xmlValidateNamesValueInternal(NULL, value));
3600}
3601
3602/**
3603 * xmlValidateNmtokenValueInternal:
3604 * @doc: pointer to the document or NULL
3605 * @value: an Nmtoken value
3606 *
3607 * Validate that the given value match Nmtoken production
3608 *
3609 * [ VC: Name Token ]
3610 *
3611 * returns 1 if valid or 0 otherwise
3612 */
3613
3614static int
3615xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00003616 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003617 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003618
3619 if (value == NULL) return(0);
3620 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003621 val = xmlStringCurrentChar(NULL, cur, &len);
3622 cur += len;
Daniel Veillardae0765b2008-07-31 19:54:59 +00003623
3624 if (!xmlIsDocNameChar(doc, val))
Owen Taylor3473f882001-02-23 17:55:21 +00003625 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003626
Daniel Veillardd8224e02002-01-13 15:43:22 +00003627 val = xmlStringCurrentChar(NULL, cur, &len);
3628 cur += len;
Daniel Veillardae0765b2008-07-31 19:54:59 +00003629 while (xmlIsDocNameChar(doc, val)) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003630 val = xmlStringCurrentChar(NULL, cur, &len);
3631 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003632 }
3633
Daniel Veillardd8224e02002-01-13 15:43:22 +00003634 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003635
3636 return(1);
3637}
3638
3639/**
3640 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003641 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003642 *
3643 * Validate that the given value match Nmtoken production
3644 *
3645 * [ VC: Name Token ]
Daniel Veillardae0765b2008-07-31 19:54:59 +00003646 *
Owen Taylor3473f882001-02-23 17:55:21 +00003647 * returns 1 if valid or 0 otherwise
3648 */
3649
Daniel Veillard9b731d72002-04-14 12:56:08 +00003650int
Owen Taylor3473f882001-02-23 17:55:21 +00003651xmlValidateNmtokenValue(const xmlChar *value) {
Daniel Veillardae0765b2008-07-31 19:54:59 +00003652 return(xmlValidateNmtokenValueInternal(NULL, value));
3653}
3654
3655/**
3656 * xmlValidateNmtokensValueInternal:
3657 * @doc: pointer to the document or NULL
3658 * @value: an Nmtokens value
3659 *
3660 * Validate that the given value match Nmtokens production
3661 *
3662 * [ VC: Name Token ]
3663 *
3664 * returns 1 if valid or 0 otherwise
3665 */
3666
3667static int
3668xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00003669 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003670 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003671
3672 if (value == NULL) return(0);
3673 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003674 val = xmlStringCurrentChar(NULL, cur, &len);
3675 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003676
Daniel Veillardae0765b2008-07-31 19:54:59 +00003677 while (IS_BLANK(val)) {
Daniel Veillardd8224e02002-01-13 15:43:22 +00003678 val = xmlStringCurrentChar(NULL, cur, &len);
3679 cur += len;
3680 }
Owen Taylor3473f882001-02-23 17:55:21 +00003681
Daniel Veillardae0765b2008-07-31 19:54:59 +00003682 if (!xmlIsDocNameChar(doc, val))
3683 return(0);
3684
3685 while (xmlIsDocNameChar(doc, val)) {
3686 val = xmlStringCurrentChar(NULL, cur, &len);
3687 cur += len;
3688 }
3689
3690 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3691 while (val == 0x20) {
3692 while (val == 0x20) {
3693 val = xmlStringCurrentChar(NULL, cur, &len);
3694 cur += len;
3695 }
3696 if (val == 0) return(1);
3697
3698 if (!xmlIsDocNameChar(doc, val))
3699 return(0);
3700
3701 val = xmlStringCurrentChar(NULL, cur, &len);
3702 cur += len;
3703
3704 while (xmlIsDocNameChar(doc, val)) {
3705 val = xmlStringCurrentChar(NULL, cur, &len);
3706 cur += len;
3707 }
3708 }
3709
Daniel Veillardd8224e02002-01-13 15:43:22 +00003710 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003711
3712 return(1);
3713}
3714
3715/**
3716 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003717 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003718 *
3719 * Validate that the given value match Nmtokens production
3720 *
3721 * [ VC: Name Token ]
Daniel Veillardae0765b2008-07-31 19:54:59 +00003722 *
Owen Taylor3473f882001-02-23 17:55:21 +00003723 * returns 1 if valid or 0 otherwise
3724 */
3725
Daniel Veillard9b731d72002-04-14 12:56:08 +00003726int
Owen Taylor3473f882001-02-23 17:55:21 +00003727xmlValidateNmtokensValue(const xmlChar *value) {
Daniel Veillardae0765b2008-07-31 19:54:59 +00003728 return(xmlValidateNmtokensValueInternal(NULL, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003729}
3730
3731/**
3732 * xmlValidateNotationDecl:
3733 * @ctxt: the validation context
3734 * @doc: a document instance
3735 * @nota: a notation definition
3736 *
3737 * Try to validate a single notation definition
3738 * basically it does the following checks as described by the
3739 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003740 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003741 * But this function get called anyway ...
3742 *
3743 * returns 1 if valid or 0 otherwise
3744 */
3745
3746int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003747xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3748 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003749 int ret = 1;
3750
3751 return(ret);
3752}
3753
3754/**
Daniel Veillardbe2bd6a2008-11-27 15:26:28 +00003755 * xmlValidateAttributeValueInternal:
3756 * @doc: the document
Owen Taylor3473f882001-02-23 17:55:21 +00003757 * @type: an attribute type
3758 * @value: an attribute value
3759 *
3760 * Validate that the given attribute value match the proper production
3761 *
Owen Taylor3473f882001-02-23 17:55:21 +00003762 * returns 1 if valid or 0 otherwise
3763 */
3764
Daniel Veillardae0765b2008-07-31 19:54:59 +00003765static int
3766xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
3767 const xmlChar *value) {
Owen Taylor3473f882001-02-23 17:55:21 +00003768 switch (type) {
3769 case XML_ATTRIBUTE_ENTITIES:
3770 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardae0765b2008-07-31 19:54:59 +00003771 return(xmlValidateNamesValueInternal(doc, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003772 case XML_ATTRIBUTE_ENTITY:
3773 case XML_ATTRIBUTE_IDREF:
3774 case XML_ATTRIBUTE_ID:
3775 case XML_ATTRIBUTE_NOTATION:
Daniel Veillardae0765b2008-07-31 19:54:59 +00003776 return(xmlValidateNameValueInternal(doc, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003777 case XML_ATTRIBUTE_NMTOKENS:
3778 case XML_ATTRIBUTE_ENUMERATION:
Daniel Veillardae0765b2008-07-31 19:54:59 +00003779 return(xmlValidateNmtokensValueInternal(doc, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003780 case XML_ATTRIBUTE_NMTOKEN:
Daniel Veillardae0765b2008-07-31 19:54:59 +00003781 return(xmlValidateNmtokenValueInternal(doc, value));
Owen Taylor3473f882001-02-23 17:55:21 +00003782 case XML_ATTRIBUTE_CDATA:
3783 break;
3784 }
3785 return(1);
3786}
3787
Daniel Veillardbe2bd6a2008-11-27 15:26:28 +00003788/**
3789 * xmlValidateAttributeValue:
3790 * @type: an attribute type
3791 * @value: an attribute value
3792 *
3793 * Validate that the given attribute value match the proper production
3794 *
3795 * [ VC: ID ]
3796 * Values of type ID must match the Name production....
3797 *
3798 * [ VC: IDREF ]
3799 * Values of type IDREF must match the Name production, and values
3800 * of type IDREFS must match Names ...
3801 *
3802 * [ VC: Entity Name ]
3803 * Values of type ENTITY must match the Name production, values
3804 * of type ENTITIES must match Names ...
3805 *
3806 * [ VC: Name Token ]
3807 * Values of type NMTOKEN must match the Nmtoken production; values
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003808 * of type NMTOKENS must match Nmtokens.
Daniel Veillardbe2bd6a2008-11-27 15:26:28 +00003809 *
3810 * returns 1 if valid or 0 otherwise
3811 */
Daniel Veillardae0765b2008-07-31 19:54:59 +00003812int
3813xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3814 return(xmlValidateAttributeValueInternal(NULL, type, value));
3815}
3816
Owen Taylor3473f882001-02-23 17:55:21 +00003817/**
3818 * xmlValidateAttributeValue2:
3819 * @ctxt: the validation context
3820 * @doc: the document
3821 * @name: the attribute name (used for error reporting only)
3822 * @type: the attribute type
3823 * @value: the attribute value
3824 *
3825 * Validate that the given attribute value match a given type.
3826 * This typically cannot be done before having finished parsing
3827 * the subsets.
3828 *
3829 * [ VC: IDREF ]
3830 * Values of type IDREF must match one of the declared IDs
3831 * Values of type IDREFS must match a sequence of the declared IDs
3832 * each Name must match the value of an ID attribute on some element
3833 * in the XML document; i.e. IDREF values must match the value of
3834 * some ID attribute
3835 *
3836 * [ VC: Entity Name ]
3837 * Values of type ENTITY must match one declared entity
3838 * Values of type ENTITIES must match a sequence of declared entities
3839 *
3840 * [ VC: Notation Attributes ]
3841 * all notation names in the declaration must be declared.
3842 *
3843 * returns 1 if valid or 0 otherwise
3844 */
3845
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003846static int
Owen Taylor3473f882001-02-23 17:55:21 +00003847xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3848 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3849 int ret = 1;
3850 switch (type) {
3851 case XML_ATTRIBUTE_IDREFS:
3852 case XML_ATTRIBUTE_IDREF:
3853 case XML_ATTRIBUTE_ID:
3854 case XML_ATTRIBUTE_NMTOKENS:
3855 case XML_ATTRIBUTE_ENUMERATION:
3856 case XML_ATTRIBUTE_NMTOKEN:
3857 case XML_ATTRIBUTE_CDATA:
3858 break;
3859 case XML_ATTRIBUTE_ENTITY: {
3860 xmlEntityPtr ent;
3861
3862 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003863 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003864 if ((ent == NULL) && (doc->standalone == 1)) {
3865 doc->standalone = 0;
3866 ent = xmlGetDocEntity(doc, value);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003867 }
Owen Taylor3473f882001-02-23 17:55:21 +00003868 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003869 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3870 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003871 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003872 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003873 ret = 0;
3874 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003875 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3876 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003877 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003878 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003879 ret = 0;
3880 }
3881 break;
3882 }
3883 case XML_ATTRIBUTE_ENTITIES: {
3884 xmlChar *dup, *nam = NULL, *cur, save;
3885 xmlEntityPtr ent;
3886
3887 dup = xmlStrdup(value);
3888 if (dup == NULL)
3889 return(0);
3890 cur = dup;
3891 while (*cur != 0) {
3892 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003893 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003894 save = *cur;
3895 *cur = 0;
3896 ent = xmlGetDocEntity(doc, nam);
3897 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003898 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3899 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003900 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003901 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003902 ret = 0;
3903 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003904 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3905 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003906 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003907 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003908 ret = 0;
3909 }
3910 if (save == 0)
3911 break;
3912 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003913 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003914 }
3915 xmlFree(dup);
3916 break;
3917 }
3918 case XML_ATTRIBUTE_NOTATION: {
3919 xmlNotationPtr nota;
3920
3921 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3922 if ((nota == NULL) && (doc->extSubset != NULL))
3923 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3924
3925 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003926 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3927 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003928 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003929 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003930 ret = 0;
3931 }
3932 break;
3933 }
3934 }
3935 return(ret);
3936}
3937
3938/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003939 * xmlValidCtxtNormalizeAttributeValue:
3940 * @ctxt: the validation context
3941 * @doc: the document
3942 * @elem: the parent
3943 * @name: the attribute name
3944 * @value: the attribute value
3945 * @ctxt: the validation context or NULL
3946 *
3947 * Does the validation related extra step of the normalization of attribute
3948 * values:
3949 *
3950 * If the declared value is not CDATA, then the XML processor must further
3951 * process the normalized attribute value by discarding any leading and
3952 * trailing space (#x20) characters, and by replacing sequences of space
3953 * (#x20) characters by single space (#x20) character.
3954 *
3955 * Also check VC: Standalone Document Declaration in P32, and update
3956 * ctxt->valid accordingly
3957 *
3958 * returns a new normalized string if normalization is needed, NULL otherwise
3959 * the caller must free the returned value.
3960 */
3961
3962xmlChar *
3963xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3964 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3965 xmlChar *ret, *dst;
3966 const xmlChar *src;
3967 xmlAttributePtr attrDecl = NULL;
3968 int extsubset = 0;
3969
3970 if (doc == NULL) return(NULL);
3971 if (elem == NULL) return(NULL);
3972 if (name == NULL) return(NULL);
3973 if (value == NULL) return(NULL);
3974
3975 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003976 xmlChar fn[50];
3977 xmlChar *fullname;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003978
Daniel Veillardc00cda82003-04-07 10:22:39 +00003979 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3980 if (fullname == NULL)
Daniel Veillard24505b02005-07-28 23:49:35 +00003981 return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00003982 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003983 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003984 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003985 if (attrDecl != NULL)
3986 extsubset = 1;
3987 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003988 if ((fullname != fn) && (fullname != elem->name))
3989 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003990 }
3991 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3992 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3993 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3994 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3995 if (attrDecl != NULL)
3996 extsubset = 1;
3997 }
3998
3999 if (attrDecl == NULL)
4000 return(NULL);
4001 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4002 return(NULL);
4003
4004 ret = xmlStrdup(value);
4005 if (ret == NULL)
4006 return(NULL);
4007 src = value;
4008 dst = ret;
4009 while (*src == 0x20) src++;
4010 while (*src != 0) {
4011 if (*src == 0x20) {
4012 while (*src == 0x20) src++;
4013 if (*src != 0)
4014 *dst++ = 0x20;
4015 } else {
4016 *dst++ = *src++;
4017 }
4018 }
4019 *dst = 0;
4020 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004021 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00004022"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004023 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00004024 ctxt->valid = 0;
4025 }
4026 return(ret);
4027}
4028
4029/**
Owen Taylor3473f882001-02-23 17:55:21 +00004030 * xmlValidNormalizeAttributeValue:
4031 * @doc: the document
4032 * @elem: the parent
4033 * @name: the attribute name
4034 * @value: the attribute value
4035 *
4036 * Does the validation related extra step of the normalization of attribute
4037 * values:
4038 *
4039 * If the declared value is not CDATA, then the XML processor must further
4040 * process the normalized attribute value by discarding any leading and
4041 * trailing space (#x20) characters, and by replacing sequences of space
4042 * (#x20) characters by single space (#x20) character.
4043 *
Daniel Veillard652327a2003-09-29 18:02:38 +00004044 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00004045 * the caller must free the returned value.
4046 */
4047
4048xmlChar *
4049xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
4050 const xmlChar *name, const xmlChar *value) {
4051 xmlChar *ret, *dst;
4052 const xmlChar *src;
4053 xmlAttributePtr attrDecl = NULL;
4054
4055 if (doc == NULL) return(NULL);
4056 if (elem == NULL) return(NULL);
4057 if (name == NULL) return(NULL);
4058 if (value == NULL) return(NULL);
4059
4060 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004061 xmlChar fn[50];
4062 xmlChar *fullname;
Daniel Veillard594e5df2009-09-07 14:58:47 +02004063
Daniel Veillardc00cda82003-04-07 10:22:39 +00004064 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4065 if (fullname == NULL)
Daniel Veillard24505b02005-07-28 23:49:35 +00004066 return(NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00004067 if ((fullname != fn) && (fullname != elem->name))
4068 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004069 }
4070 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4071 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4072 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4073
4074 if (attrDecl == NULL)
4075 return(NULL);
4076 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4077 return(NULL);
4078
4079 ret = xmlStrdup(value);
4080 if (ret == NULL)
4081 return(NULL);
4082 src = value;
4083 dst = ret;
4084 while (*src == 0x20) src++;
4085 while (*src != 0) {
4086 if (*src == 0x20) {
4087 while (*src == 0x20) src++;
4088 if (*src != 0)
4089 *dst++ = 0x20;
4090 } else {
4091 *dst++ = *src++;
4092 }
4093 }
4094 *dst = 0;
4095 return(ret);
4096}
4097
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004098static void
Owen Taylor3473f882001-02-23 17:55:21 +00004099xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00004100 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00004101 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4102}
4103
4104/**
4105 * xmlValidateAttributeDecl:
4106 * @ctxt: the validation context
4107 * @doc: a document instance
4108 * @attr: an attribute definition
4109 *
4110 * Try to validate a single attribute definition
4111 * basically it does the following checks as described by the
4112 * XML-1.0 recommendation:
4113 * - [ VC: Attribute Default Legal ]
4114 * - [ VC: Enumeration ]
4115 * - [ VC: ID Attribute Default ]
4116 *
4117 * The ID/IDREF uniqueness and matching are done separately
4118 *
4119 * returns 1 if valid or 0 otherwise
4120 */
4121
4122int
4123xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4124 xmlAttributePtr attr) {
4125 int ret = 1;
4126 int val;
4127 CHECK_DTD;
4128 if(attr == NULL) return(1);
Daniel Veillardae0765b2008-07-31 19:54:59 +00004129
Owen Taylor3473f882001-02-23 17:55:21 +00004130 /* Attribute Default Legal */
4131 /* Enumeration */
4132 if (attr->defaultValue != NULL) {
Daniel Veillardae0765b2008-07-31 19:54:59 +00004133 val = xmlValidateAttributeValueInternal(doc, attr->atype,
4134 attr->defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00004135 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004136 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004137 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004138 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004139 }
4140 ret &= val;
4141 }
4142
4143 /* ID Attribute Default */
4144 if ((attr->atype == XML_ATTRIBUTE_ID)&&
4145 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4146 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004147 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004148 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004149 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004150 ret = 0;
4151 }
4152
4153 /* One ID per Element Type */
4154 if (attr->atype == XML_ATTRIBUTE_ID) {
4155 int nbId;
4156
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004157 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00004158 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4159 attr->elem);
4160 if (elem != NULL) {
Daniel Veillarddbee0f12005-06-27 13:42:57 +00004161 nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00004162 } else {
4163 xmlAttributeTablePtr table;
4164
4165 /*
4166 * The attribute may be declared in the internal subset and the
4167 * element in the external subset.
4168 */
4169 nbId = 0;
Daniel Veillard11ce4002006-03-10 00:36:23 +00004170 if (doc->intSubset != NULL) {
4171 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4172 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
4173 xmlValidateAttributeIdCallback, &nbId);
4174 }
Owen Taylor3473f882001-02-23 17:55:21 +00004175 }
4176 if (nbId > 1) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004177
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004178 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004179 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4180 attr->elem, nbId, attr->name);
4181 } else if (doc->extSubset != NULL) {
4182 int extId = 0;
4183 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4184 if (elem != NULL) {
Daniel Veillarddbee0f12005-06-27 13:42:57 +00004185 extId = xmlScanIDAttributeDecl(NULL, elem, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00004186 }
4187 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004188 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004189 "Element %s has %d ID attribute defined in the external subset : %s\n",
4190 attr->elem, extId, attr->name);
4191 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004192 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00004193"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004194 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004195 }
4196 }
4197 }
4198
4199 /* Validity Constraint: Enumeration */
4200 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4201 xmlEnumerationPtr tree = attr->tree;
4202 while (tree != NULL) {
4203 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4204 tree = tree->next;
4205 }
4206 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004207 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004208"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004209 attr->defaultValue, attr->name, attr->elem);
4210 ret = 0;
4211 }
4212 }
4213
4214 return(ret);
4215}
4216
4217/**
4218 * xmlValidateElementDecl:
4219 * @ctxt: the validation context
4220 * @doc: a document instance
4221 * @elem: an element definition
4222 *
4223 * Try to validate a single element definition
4224 * basically it does the following checks as described by the
4225 * XML-1.0 recommendation:
4226 * - [ VC: One ID per Element Type ]
4227 * - [ VC: No Duplicate Types ]
4228 * - [ VC: Unique Element Type Declaration ]
4229 *
4230 * returns 1 if valid or 0 otherwise
4231 */
4232
4233int
4234xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4235 xmlElementPtr elem) {
4236 int ret = 1;
4237 xmlElementPtr tst;
4238
4239 CHECK_DTD;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004240
Owen Taylor3473f882001-02-23 17:55:21 +00004241 if (elem == NULL) return(1);
4242
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004243#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00004244#ifdef LIBXML_REGEXP_ENABLED
4245 /* Build the regexp associated to the content model */
4246 ret = xmlValidBuildContentModel(ctxt, elem);
4247#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004248#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00004249
Owen Taylor3473f882001-02-23 17:55:21 +00004250 /* No Duplicate Types */
4251 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4252 xmlElementContentPtr cur, next;
4253 const xmlChar *name;
4254
4255 cur = elem->content;
4256 while (cur != NULL) {
4257 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4258 if (cur->c1 == NULL) break;
4259 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4260 name = cur->c1->name;
4261 next = cur->c2;
4262 while (next != NULL) {
4263 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00004264 if ((xmlStrEqual(next->name, name)) &&
Daniel Veillarda7216122009-08-21 18:22:58 +02004265 (xmlStrEqual(next->prefix, cur->c1->prefix))) {
4266 if (cur->c1->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004267 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00004268 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004269 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004270 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004271 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004272 "Definition of %s has duplicate references of %s:%s\n",
Daniel Veillarda7216122009-08-21 18:22:58 +02004273 elem->name, cur->c1->prefix, name);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004274 }
Owen Taylor3473f882001-02-23 17:55:21 +00004275 ret = 0;
4276 }
4277 break;
4278 }
4279 if (next->c1 == NULL) break;
4280 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00004281 if ((xmlStrEqual(next->c1->name, name)) &&
Daniel Veillarda7216122009-08-21 18:22:58 +02004282 (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
4283 if (cur->c1->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004284 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004285 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004286 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004287 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004288 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00004289 "Definition of %s has duplicate references to %s:%s\n",
Daniel Veillarda7216122009-08-21 18:22:58 +02004290 elem->name, cur->c1->prefix, name);
Daniel Veillard7b68df92003-08-03 22:58:54 +00004291 }
Owen Taylor3473f882001-02-23 17:55:21 +00004292 ret = 0;
4293 }
4294 next = next->c2;
4295 }
4296 }
4297 cur = cur->c2;
4298 }
4299 }
4300
4301 /* VC: Unique Element Type Declaration */
4302 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004303 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004304 ((tst->prefix == elem->prefix) ||
4305 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004306 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004307 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4308 "Redefinition of element %s\n",
4309 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004310 ret = 0;
4311 }
4312 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00004313 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004314 ((tst->prefix == elem->prefix) ||
4315 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00004316 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004317 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4318 "Redefinition of element %s\n",
4319 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004320 ret = 0;
4321 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004322 /* One ID per Element Type
4323 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004324 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4325 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004326 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004327 return(ret);
4328}
4329
4330/**
4331 * xmlValidateOneAttribute:
4332 * @ctxt: the validation context
4333 * @doc: a document instance
4334 * @elem: an element instance
4335 * @attr: an attribute instance
4336 * @value: the attribute value (without entities processing)
4337 *
4338 * Try to validate a single attribute for an element
4339 * basically it does the following checks as described by the
4340 * XML-1.0 recommendation:
4341 * - [ VC: Attribute Value Type ]
4342 * - [ VC: Fixed Attribute Default ]
4343 * - [ VC: Entity Name ]
4344 * - [ VC: Name Token ]
4345 * - [ VC: ID ]
4346 * - [ VC: IDREF ]
4347 * - [ VC: Entity Name ]
4348 * - [ VC: Notation Attributes ]
4349 *
4350 * The ID/IDREF uniqueness and matching are done separately
4351 *
4352 * returns 1 if valid or 0 otherwise
4353 */
4354
4355int
4356xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004357 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
Daniel Veillard07cb8222003-09-10 10:51:05 +00004358{
Owen Taylor3473f882001-02-23 17:55:21 +00004359 xmlAttributePtr attrDecl = NULL;
4360 int val;
4361 int ret = 1;
4362
4363 CHECK_DTD;
4364 if ((elem == NULL) || (elem->name == NULL)) return(0);
4365 if ((attr == NULL) || (attr->name == NULL)) return(0);
4366
4367 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004368 xmlChar fn[50];
4369 xmlChar *fullname;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004370
Daniel Veillardc00cda82003-04-07 10:22:39 +00004371 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4372 if (fullname == NULL)
4373 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004374 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004375 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004376 attr->name, attr->ns->prefix);
4377 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004378 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004379 attr->name, attr->ns->prefix);
4380 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004381 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004382 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4383 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004384 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004385 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004386 if ((fullname != fn) && (fullname != elem->name))
4387 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004388 }
4389 if (attrDecl == NULL) {
4390 if (attr->ns != NULL) {
4391 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4392 attr->name, attr->ns->prefix);
4393 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4394 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4395 attr->name, attr->ns->prefix);
4396 } else {
4397 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4398 elem->name, attr->name);
4399 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4400 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4401 elem->name, attr->name);
4402 }
4403 }
4404
4405
4406 /* Validity Constraint: Attribute Value Type */
4407 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004408 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004409 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004410 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004411 return(0);
4412 }
4413 attr->atype = attrDecl->atype;
4414
Daniel Veillardae0765b2008-07-31 19:54:59 +00004415 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
Owen Taylor3473f882001-02-23 17:55:21 +00004416 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004417 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004418 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004419 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004420 ret = 0;
4421 }
4422
4423 /* Validity constraint: Fixed Attribute Default */
4424 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4425 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004426 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004427 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004428 attr->name, elem->name, attrDecl->defaultValue);
4429 ret = 0;
4430 }
4431 }
4432
4433 /* Validity Constraint: ID uniqueness */
4434 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4435 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4436 ret = 0;
4437 }
4438
4439 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4440 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4441 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4442 ret = 0;
4443 }
4444
4445 /* Validity Constraint: Notation Attributes */
4446 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4447 xmlEnumerationPtr tree = attrDecl->tree;
4448 xmlNotationPtr nota;
4449
4450 /* First check that the given NOTATION was declared */
4451 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4452 if (nota == NULL)
4453 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004454
Owen Taylor3473f882001-02-23 17:55:21 +00004455 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004456 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004457 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004458 value, attr->name, elem->name);
4459 ret = 0;
4460 }
4461
4462 /* Second, verify that it's among the list */
4463 while (tree != NULL) {
4464 if (xmlStrEqual(tree->name, value)) break;
4465 tree = tree->next;
4466 }
4467 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004468 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004469"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004470 value, attr->name, elem->name);
4471 ret = 0;
4472 }
4473 }
4474
4475 /* Validity Constraint: Enumeration */
4476 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4477 xmlEnumerationPtr tree = attrDecl->tree;
4478 while (tree != NULL) {
4479 if (xmlStrEqual(tree->name, value)) break;
4480 tree = tree->next;
4481 }
4482 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004483 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004484 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004485 value, attr->name, elem->name);
4486 ret = 0;
4487 }
4488 }
4489
4490 /* Fixed Attribute Default */
4491 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4492 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004493 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004494 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004495 attr->name, elem->name, attrDecl->defaultValue);
4496 ret = 0;
4497 }
4498
4499 /* Extra check for the attribute value */
4500 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4501 attrDecl->atype, value);
4502
4503 return(ret);
4504}
4505
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004506/**
4507 * xmlValidateOneNamespace:
4508 * @ctxt: the validation context
4509 * @doc: a document instance
4510 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004511 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004512 * @ns: an namespace declaration instance
4513 * @value: the attribute value (without entities processing)
4514 *
4515 * Try to validate a single namespace declaration for an element
4516 * basically it does the following checks as described by the
4517 * XML-1.0 recommendation:
4518 * - [ VC: Attribute Value Type ]
4519 * - [ VC: Fixed Attribute Default ]
4520 * - [ VC: Entity Name ]
4521 * - [ VC: Name Token ]
4522 * - [ VC: ID ]
4523 * - [ VC: IDREF ]
4524 * - [ VC: Entity Name ]
4525 * - [ VC: Notation Attributes ]
4526 *
4527 * The ID/IDREF uniqueness and matching are done separately
4528 *
4529 * returns 1 if valid or 0 otherwise
4530 */
4531
4532int
4533xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4534xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4535 /* xmlElementPtr elemDecl; */
4536 xmlAttributePtr attrDecl = NULL;
4537 int val;
4538 int ret = 1;
4539
4540 CHECK_DTD;
4541 if ((elem == NULL) || (elem->name == NULL)) return(0);
4542 if ((ns == NULL) || (ns->href == NULL)) return(0);
4543
4544 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004545 xmlChar fn[50];
4546 xmlChar *fullname;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004547
Daniel Veillardc00cda82003-04-07 10:22:39 +00004548 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4549 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004550 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004551 return(0);
4552 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004553 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004554 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004555 ns->prefix, BAD_CAST "xmlns");
4556 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004557 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004558 ns->prefix, BAD_CAST "xmlns");
4559 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004560 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004561 BAD_CAST "xmlns");
4562 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004563 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004564 BAD_CAST "xmlns");
4565 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004566 if ((fullname != fn) && (fullname != elem->name))
4567 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004568 }
4569 if (attrDecl == NULL) {
4570 if (ns->prefix != NULL) {
4571 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4572 ns->prefix, BAD_CAST "xmlns");
4573 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4574 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4575 ns->prefix, BAD_CAST "xmlns");
4576 } else {
4577 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4578 elem->name, BAD_CAST "xmlns");
4579 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4580 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4581 elem->name, BAD_CAST "xmlns");
4582 }
4583 }
4584
4585
4586 /* Validity Constraint: Attribute Value Type */
4587 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004588 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004589 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004590 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004591 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004592 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004593 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004594 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004595 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004596 }
4597 return(0);
4598 }
4599
Daniel Veillardae0765b2008-07-31 19:54:59 +00004600 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004601 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004602 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004603 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004604 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004605 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004606 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004607 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004608 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004609 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004610 }
4611 ret = 0;
4612 }
4613
4614 /* Validity constraint: Fixed Attribute Default */
4615 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4616 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004617 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004618 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004619 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4620 ns->prefix, elem->name, attrDecl->defaultValue);
4621 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004622 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004623 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004624 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004625 }
4626 ret = 0;
4627 }
4628 }
4629
Nick Wellnhofer92b9e8c2017-06-06 12:56:28 +02004630 /*
4631 * Casting ns to xmlAttrPtr is wrong. We'd need separate functions
4632 * xmlAddID and xmlAddRef for namespace declarations, but it makes
4633 * no practical sense to use ID types anyway.
4634 */
4635#if 0
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004636 /* Validity Constraint: ID uniqueness */
4637 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4638 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4639 ret = 0;
4640 }
4641
4642 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4643 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4644 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4645 ret = 0;
4646 }
Nick Wellnhofer92b9e8c2017-06-06 12:56:28 +02004647#endif
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004648
4649 /* Validity Constraint: Notation Attributes */
4650 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4651 xmlEnumerationPtr tree = attrDecl->tree;
4652 xmlNotationPtr nota;
4653
4654 /* First check that the given NOTATION was declared */
4655 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4656 if (nota == NULL)
4657 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004658
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004659 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004660 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004661 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004662 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4663 value, ns->prefix, elem->name);
4664 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004665 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004666 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004667 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004668 }
4669 ret = 0;
4670 }
4671
4672 /* Second, verify that it's among the list */
4673 while (tree != NULL) {
4674 if (xmlStrEqual(tree->name, value)) break;
4675 tree = tree->next;
4676 }
4677 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004678 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004679 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004680"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4681 value, ns->prefix, elem->name);
4682 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004683 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004684"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004685 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004686 }
4687 ret = 0;
4688 }
4689 }
4690
4691 /* Validity Constraint: Enumeration */
4692 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4693 xmlEnumerationPtr tree = attrDecl->tree;
4694 while (tree != NULL) {
4695 if (xmlStrEqual(tree->name, value)) break;
4696 tree = tree->next;
4697 }
4698 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004699 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004700 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004701"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4702 value, ns->prefix, elem->name);
4703 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004704 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004705"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004706 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004707 }
4708 ret = 0;
4709 }
4710 }
4711
4712 /* Fixed Attribute Default */
4713 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4714 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004715 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004716 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004717 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4718 ns->prefix, elem->name, attrDecl->defaultValue);
4719 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004720 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004721 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004722 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004723 }
4724 ret = 0;
4725 }
4726
4727 /* Extra check for the attribute value */
4728 if (ns->prefix != NULL) {
4729 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4730 attrDecl->atype, value);
4731 } else {
4732 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4733 attrDecl->atype, value);
4734 }
4735
4736 return(ret);
4737}
4738
Daniel Veillard118aed72002-09-24 14:13:13 +00004739#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004740/**
4741 * xmlValidateSkipIgnorable:
4742 * @ctxt: the validation context
4743 * @child: the child list
4744 *
4745 * Skip ignorable elements w.r.t. the validation process
4746 *
4747 * returns the first element to consider for validation of the content model
4748 */
4749
4750static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004751xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004752 while (child != NULL) {
4753 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004754 /* These things are ignored (skipped) during validation. */
4755 case XML_PI_NODE:
4756 case XML_COMMENT_NODE:
4757 case XML_XINCLUDE_START:
4758 case XML_XINCLUDE_END:
4759 child = child->next;
4760 break;
4761 case XML_TEXT_NODE:
4762 if (xmlIsBlankNode(child))
4763 child = child->next;
4764 else
4765 return(child);
4766 break;
4767 /* keep current node */
4768 default:
4769 return(child);
4770 }
4771 }
4772 return(child);
4773}
4774
4775/**
4776 * xmlValidateElementType:
4777 * @ctxt: the validation context
4778 *
4779 * Try to validate the content model of an element internal function
4780 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004781 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4782 * reference is found and -3 if the validation succeeded but
4783 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004784 */
4785
4786static int
4787xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004788 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004789 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004790
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004791 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004792 if ((NODE == NULL) && (CONT == NULL))
4793 return(1);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08004794 if ((NODE == NULL) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004795 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4796 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4797 return(1);
4798 }
4799 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004800 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004801 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004802
4803 /*
4804 * We arrive here when more states need to be examined
4805 */
4806cont:
4807
4808 /*
4809 * We just recovered from a rollback generated by a possible
4810 * epsilon transition, go directly to the analysis phase
4811 */
4812 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004813 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004814 DEBUG_VALID_STATE(NODE, CONT)
4815 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004816 goto analyze;
4817 }
4818
4819 DEBUG_VALID_STATE(NODE, CONT)
4820 /*
4821 * we may have to save a backup state here. This is the equivalent
4822 * of handling epsilon transition in NFAs.
4823 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004824 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004825 ((CONT->parent == NULL) ||
4826 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004827 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004828 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004829 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004830 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004831 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4832 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004833 }
4834
4835
4836 /*
4837 * Check first if the content matches
4838 */
4839 switch (CONT->type) {
4840 case XML_ELEMENT_CONTENT_PCDATA:
4841 if (NODE == NULL) {
4842 DEBUG_VALID_MSG("pcdata failed no node");
4843 ret = 0;
4844 break;
4845 }
4846 if (NODE->type == XML_TEXT_NODE) {
4847 DEBUG_VALID_MSG("pcdata found, skip to next");
4848 /*
4849 * go to next element in the content model
4850 * skipping ignorable elems
4851 */
4852 do {
4853 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004854 NODE = xmlValidateSkipIgnorable(NODE);
4855 if ((NODE != NULL) &&
4856 (NODE->type == XML_ENTITY_REF_NODE))
4857 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004858 } while ((NODE != NULL) &&
4859 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004860 (NODE->type != XML_TEXT_NODE) &&
4861 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004862 ret = 1;
4863 break;
4864 } else {
4865 DEBUG_VALID_MSG("pcdata failed");
4866 ret = 0;
4867 break;
4868 }
4869 break;
4870 case XML_ELEMENT_CONTENT_ELEMENT:
4871 if (NODE == NULL) {
4872 DEBUG_VALID_MSG("element failed no node");
4873 ret = 0;
4874 break;
4875 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004876 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4877 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004878 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004879 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4880 ret = (CONT->prefix == NULL);
4881 } else if (CONT->prefix == NULL) {
4882 ret = 0;
4883 } else {
4884 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4885 }
4886 }
4887 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004888 DEBUG_VALID_MSG("element found, skip to next");
4889 /*
4890 * go to next element in the content model
4891 * skipping ignorable elems
4892 */
4893 do {
4894 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004895 NODE = xmlValidateSkipIgnorable(NODE);
4896 if ((NODE != NULL) &&
4897 (NODE->type == XML_ENTITY_REF_NODE))
4898 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004899 } while ((NODE != NULL) &&
4900 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004901 (NODE->type != XML_TEXT_NODE) &&
4902 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004903 } else {
4904 DEBUG_VALID_MSG("element failed");
4905 ret = 0;
4906 break;
4907 }
4908 break;
4909 case XML_ELEMENT_CONTENT_OR:
4910 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004911 * Small optimization.
4912 */
4913 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4914 if ((NODE == NULL) ||
4915 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4916 DEPTH++;
4917 CONT = CONT->c2;
4918 goto cont;
4919 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004920 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4921 ret = (CONT->c1->prefix == NULL);
4922 } else if (CONT->c1->prefix == NULL) {
4923 ret = 0;
4924 } else {
4925 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4926 }
4927 if (ret == 0) {
4928 DEPTH++;
4929 CONT = CONT->c2;
4930 goto cont;
4931 }
Daniel Veillard85349052001-04-20 13:48:21 +00004932 }
4933
4934 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004935 * save the second branch 'or' branch
4936 */
4937 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004938 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4939 OCCURS, ROLLBACK_OR) < 0)
4940 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004941 DEPTH++;
4942 CONT = CONT->c1;
4943 goto cont;
4944 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004945 /*
4946 * Small optimization.
4947 */
4948 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4949 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4950 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4951 if ((NODE == NULL) ||
4952 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4953 DEPTH++;
4954 CONT = CONT->c2;
4955 goto cont;
4956 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004957 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4958 ret = (CONT->c1->prefix == NULL);
4959 } else if (CONT->c1->prefix == NULL) {
4960 ret = 0;
4961 } else {
4962 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4963 }
4964 if (ret == 0) {
4965 DEPTH++;
4966 CONT = CONT->c2;
4967 goto cont;
4968 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004969 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004970 DEPTH++;
4971 CONT = CONT->c1;
4972 goto cont;
4973 }
4974
4975 /*
4976 * At this point handle going up in the tree
4977 */
4978 if (ret == -1) {
4979 DEBUG_VALID_MSG("error found returning");
4980 return(ret);
4981 }
4982analyze:
4983 while (CONT != NULL) {
4984 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004985 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004986 * this level.
4987 */
4988 if (ret == 0) {
4989 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004990 xmlNodePtr cur;
4991
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004992 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004993 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004994 DEBUG_VALID_MSG("Once branch failed, rollback");
4995 if (vstateVPop(ctxt) < 0 ) {
4996 DEBUG_VALID_MSG("exhaustion, failed");
4997 return(0);
4998 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004999 if (cur != ctxt->vstate->node)
5000 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005001 goto cont;
5002 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00005003 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005004 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005005 DEBUG_VALID_MSG("Plus branch failed, rollback");
5006 if (vstateVPop(ctxt) < 0 ) {
5007 DEBUG_VALID_MSG("exhaustion, failed");
5008 return(0);
5009 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005010 if (cur != ctxt->vstate->node)
5011 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005012 goto cont;
5013 }
5014 DEBUG_VALID_MSG("Plus branch found");
5015 ret = 1;
5016 break;
5017 case XML_ELEMENT_CONTENT_MULT:
5018#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00005019 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005020 DEBUG_VALID_MSG("Mult branch failed");
5021 } else {
5022 DEBUG_VALID_MSG("Mult branch found");
5023 }
5024#endif
5025 ret = 1;
5026 break;
5027 case XML_ELEMENT_CONTENT_OPT:
5028 DEBUG_VALID_MSG("Option branch failed");
5029 ret = 1;
5030 break;
5031 }
5032 } else {
5033 switch (CONT->ocur) {
5034 case XML_ELEMENT_CONTENT_OPT:
5035 DEBUG_VALID_MSG("Option branch succeeded");
5036 ret = 1;
5037 break;
5038 case XML_ELEMENT_CONTENT_ONCE:
5039 DEBUG_VALID_MSG("Once branch succeeded");
5040 ret = 1;
5041 break;
5042 case XML_ELEMENT_CONTENT_PLUS:
5043 if (STATE == ROLLBACK_PARENT) {
5044 DEBUG_VALID_MSG("Plus branch rollback");
5045 ret = 1;
5046 break;
5047 }
5048 if (NODE == NULL) {
5049 DEBUG_VALID_MSG("Plus branch exhausted");
5050 ret = 1;
5051 break;
5052 }
5053 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00005054 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005055 goto cont;
5056 case XML_ELEMENT_CONTENT_MULT:
5057 if (STATE == ROLLBACK_PARENT) {
5058 DEBUG_VALID_MSG("Mult branch rollback");
5059 ret = 1;
5060 break;
5061 }
5062 if (NODE == NULL) {
5063 DEBUG_VALID_MSG("Mult branch exhausted");
5064 ret = 1;
5065 break;
5066 }
5067 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00005068 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005069 goto cont;
5070 }
5071 }
5072 STATE = 0;
5073
5074 /*
5075 * Then act accordingly at the parent level
5076 */
Daniel Veillard5344c602001-12-31 16:37:34 +00005077 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005078 if (CONT->parent == NULL)
5079 break;
5080
5081 switch (CONT->parent->type) {
5082 case XML_ELEMENT_CONTENT_PCDATA:
5083 DEBUG_VALID_MSG("Error: parent pcdata");
5084 return(-1);
5085 case XML_ELEMENT_CONTENT_ELEMENT:
5086 DEBUG_VALID_MSG("Error: parent element");
5087 return(-1);
5088 case XML_ELEMENT_CONTENT_OR:
5089 if (ret == 1) {
5090 DEBUG_VALID_MSG("Or succeeded");
5091 CONT = CONT->parent;
5092 DEPTH--;
5093 } else {
5094 DEBUG_VALID_MSG("Or failed");
5095 CONT = CONT->parent;
5096 DEPTH--;
5097 }
5098 break;
5099 case XML_ELEMENT_CONTENT_SEQ:
5100 if (ret == 0) {
5101 DEBUG_VALID_MSG("Sequence failed");
5102 CONT = CONT->parent;
5103 DEPTH--;
5104 } else if (CONT == CONT->parent->c1) {
5105 DEBUG_VALID_MSG("Sequence testing 2nd branch");
5106 CONT = CONT->parent->c2;
5107 goto cont;
5108 } else {
5109 DEBUG_VALID_MSG("Sequence succeeded");
5110 CONT = CONT->parent;
5111 DEPTH--;
5112 }
5113 }
5114 }
5115 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005116 xmlNodePtr cur;
5117
5118 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005119 DEBUG_VALID_MSG("Failed, remaining input, rollback");
5120 if (vstateVPop(ctxt) < 0 ) {
5121 DEBUG_VALID_MSG("exhaustion, failed");
5122 return(0);
5123 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005124 if (cur != ctxt->vstate->node)
5125 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005126 goto cont;
5127 }
5128 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005129 xmlNodePtr cur;
5130
5131 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005132 DEBUG_VALID_MSG("Failure, rollback");
5133 if (vstateVPop(ctxt) < 0 ) {
5134 DEBUG_VALID_MSG("exhaustion, failed");
5135 return(0);
5136 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005137 if (cur != ctxt->vstate->node)
5138 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005139 goto cont;
5140 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005141 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005142}
Daniel Veillard23e73572002-09-19 19:56:43 +00005143#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005144
5145/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00005146 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005147 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00005148 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005149 * @content: An element
5150 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5151 *
5152 * This will dump the list of elements to the buffer
5153 * Intended just for the debug routine
5154 */
5155static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00005156xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005157 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00005158 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005159
5160 if (node == NULL) return;
5161 if (glob) strcat(buf, "(");
5162 cur = node;
5163 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005164 len = strlen(buf);
5165 if (size - len < 50) {
5166 if ((size - len > 4) && (buf[len - 1] != '.'))
5167 strcat(buf, " ...");
5168 return;
5169 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005170 switch (cur->type) {
5171 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005172 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005173 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005174 if ((size - len > 4) && (buf[len - 1] != '.'))
5175 strcat(buf, " ...");
5176 return;
5177 }
5178 strcat(buf, (char *) cur->ns->prefix);
5179 strcat(buf, ":");
5180 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00005181 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00005182 if ((size - len > 4) && (buf[len - 1] != '.'))
5183 strcat(buf, " ...");
5184 return;
5185 }
5186 strcat(buf, (char *) cur->name);
5187 if (cur->next != NULL)
5188 strcat(buf, " ");
5189 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005190 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005191 if (xmlIsBlankNode(cur))
5192 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005193 case XML_CDATA_SECTION_NODE:
5194 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005195 strcat(buf, "CDATA");
5196 if (cur->next != NULL)
5197 strcat(buf, " ");
5198 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005199 case XML_ATTRIBUTE_NODE:
5200 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005201#ifdef LIBXML_DOCB_ENABLED
5202 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005203#endif
5204 case XML_HTML_DOCUMENT_NODE:
5205 case XML_DOCUMENT_TYPE_NODE:
5206 case XML_DOCUMENT_FRAG_NODE:
5207 case XML_NOTATION_NODE:
5208 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005209 strcat(buf, "???");
5210 if (cur->next != NULL)
5211 strcat(buf, " ");
5212 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005213 case XML_ENTITY_NODE:
5214 case XML_PI_NODE:
5215 case XML_DTD_NODE:
5216 case XML_COMMENT_NODE:
5217 case XML_ELEMENT_DECL:
5218 case XML_ATTRIBUTE_DECL:
5219 case XML_ENTITY_DECL:
5220 case XML_XINCLUDE_START:
5221 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00005222 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005223 }
5224 cur = cur->next;
5225 }
5226 if (glob) strcat(buf, ")");
5227}
5228
5229/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005230 * xmlValidateElementContent:
5231 * @ctxt: the validation context
5232 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005233 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005234 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005235 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005236 *
5237 * Try to validate the content model of an element
5238 *
5239 * returns 1 if valid or 0 if not and -1 in case of error
5240 */
5241
5242static int
5243xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005244 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00005245 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00005246#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00005247 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00005248#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00005249 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005250 xmlElementContentPtr cont;
5251 const xmlChar *name;
5252
Gauravc570b372013-09-30 10:43:47 +08005253 if ((elemDecl == NULL) || (parent == NULL) || (ctxt == NULL))
Daniel Veillardbe480fb2001-11-08 23:36:42 +00005254 return(-1);
5255 cont = elemDecl->content;
5256 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005257
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005258#ifdef LIBXML_REGEXP_ENABLED
5259 /* Build the regexp associated to the content model */
5260 if (elemDecl->contModel == NULL)
5261 ret = xmlValidBuildContentModel(ctxt, elemDecl);
5262 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005263 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005264 } else {
5265 xmlRegExecCtxtPtr exec;
5266
Daniel Veillardec498e12003-02-05 11:01:50 +00005267 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5268 return(-1);
5269 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005270 ctxt->nodeMax = 0;
5271 ctxt->nodeNr = 0;
5272 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005273 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5274 if (exec != NULL) {
5275 cur = child;
5276 while (cur != NULL) {
5277 switch (cur->type) {
5278 case XML_ENTITY_REF_NODE:
5279 /*
5280 * Push the current node to be able to roll back
5281 * and process within the entity
5282 */
5283 if ((cur->children != NULL) &&
5284 (cur->children->children != NULL)) {
5285 nodeVPush(ctxt, cur);
5286 cur = cur->children->children;
5287 continue;
5288 }
5289 break;
5290 case XML_TEXT_NODE:
5291 if (xmlIsBlankNode(cur))
5292 break;
5293 ret = 0;
5294 goto fail;
5295 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00005296 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005297 ret = 0;
5298 goto fail;
5299 case XML_ELEMENT_NODE:
5300 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005301 xmlChar fn[50];
5302 xmlChar *fullname;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005303
Daniel Veillardc00cda82003-04-07 10:22:39 +00005304 fullname = xmlBuildQName(cur->name,
5305 cur->ns->prefix, fn, 50);
5306 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005307 ret = -1;
5308 goto fail;
5309 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005310 ret = xmlRegExecPushString(exec, fullname, NULL);
5311 if ((fullname != fn) && (fullname != cur->name))
5312 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005313 } else {
5314 ret = xmlRegExecPushString(exec, cur->name, NULL);
5315 }
5316 break;
5317 default:
5318 break;
5319 }
5320 /*
5321 * Switch to next element
5322 */
5323 cur = cur->next;
5324 while (cur == NULL) {
5325 cur = nodeVPop(ctxt);
5326 if (cur == NULL)
5327 break;
5328 cur = cur->next;
5329 }
5330 }
5331 ret = xmlRegExecPushString(exec, NULL, NULL);
5332fail:
5333 xmlRegFreeExecCtxt(exec);
5334 }
5335 }
5336#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005337 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005338 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005339 */
5340 ctxt->vstateMax = 8;
5341 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5342 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5343 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005344 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005345 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005346 }
5347 /*
5348 * The first entry in the stack is reserved to the current state
5349 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005350 ctxt->nodeMax = 0;
5351 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005352 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005353 ctxt->vstate = &ctxt->vstateTab[0];
5354 ctxt->vstateNr = 1;
5355 CONT = cont;
5356 NODE = child;
5357 DEPTH = 0;
5358 OCCURS = 0;
5359 STATE = 0;
5360 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005361 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005362 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5363 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005364 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005365 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005366 /*
5367 * An entities reference appeared at this level.
5368 * Buid a minimal representation of this node content
5369 * sufficient to run the validation process on it
5370 */
5371 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005372 cur = child;
5373 while (cur != NULL) {
5374 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005375 case XML_ENTITY_REF_NODE:
5376 /*
5377 * Push the current node to be able to roll back
5378 * and process within the entity
5379 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005380 if ((cur->children != NULL) &&
5381 (cur->children->children != NULL)) {
5382 nodeVPush(ctxt, cur);
5383 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005384 continue;
5385 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005386 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005387 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005388 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005389 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005390 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005391 case XML_CDATA_SECTION_NODE:
5392 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005393 case XML_ELEMENT_NODE:
5394 /*
5395 * Allocate a new node and minimally fills in
5396 * what's required
5397 */
5398 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5399 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005400 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005401 xmlFreeNodeList(repl);
5402 ret = -1;
5403 goto done;
5404 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005405 tmp->type = cur->type;
5406 tmp->name = cur->name;
5407 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005408 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005409 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005410 if (repl == NULL)
5411 repl = last = tmp;
5412 else {
5413 last->next = tmp;
5414 last = tmp;
5415 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005416 if (cur->type == XML_CDATA_SECTION_NODE) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005417 /*
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005418 * E59 spaces in CDATA does not match the
5419 * nonterminal S
5420 */
5421 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5422 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005423 break;
5424 default:
5425 break;
5426 }
5427 /*
5428 * Switch to next element
5429 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005430 cur = cur->next;
5431 while (cur == NULL) {
5432 cur = nodeVPop(ctxt);
5433 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005434 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005435 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005436 }
5437 }
5438
5439 /*
5440 * Relaunch the validation
5441 */
5442 ctxt->vstate = &ctxt->vstateTab[0];
5443 ctxt->vstateNr = 1;
5444 CONT = cont;
5445 NODE = repl;
5446 DEPTH = 0;
5447 OCCURS = 0;
5448 STATE = 0;
5449 ret = xmlValidateElementType(ctxt);
5450 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005451#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005452 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00005453 if (ctxt != NULL) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005454 char expr[5000];
5455 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005456
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005457 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005458 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005459 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005460#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005461 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005462 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005463 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005464#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005465 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005466
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005467 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005468 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5469 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5470 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005471 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005472 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5473 "Element content does not follow the DTD, expecting %s, got %s\n",
5474 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005475 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005476 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005477 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005478 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005479 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005480 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005481 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005482 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5483 "Element content does not follow the DTD\n",
5484 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005485 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005486 }
5487 ret = 0;
5488 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005489 if (ret == -3)
5490 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005491
Daniel Veillard23e73572002-09-19 19:56:43 +00005492#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005493done:
5494 /*
5495 * Deallocate the copy if done, and free up the validation stack
5496 */
5497 while (repl != NULL) {
5498 tmp = repl->next;
5499 xmlFree(repl);
5500 repl = tmp;
5501 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005502 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005503 if (ctxt->vstateTab != NULL) {
5504 xmlFree(ctxt->vstateTab);
5505 ctxt->vstateTab = NULL;
5506 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005507#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005508 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005509 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005510 if (ctxt->nodeTab != NULL) {
5511 xmlFree(ctxt->nodeTab);
5512 ctxt->nodeTab = NULL;
5513 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005514 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005515
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005516}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005517
Owen Taylor3473f882001-02-23 17:55:21 +00005518/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005519 * xmlValidateCdataElement:
5520 * @ctxt: the validation context
5521 * @doc: a document instance
5522 * @elem: an element instance
5523 *
5524 * Check that an element follows #CDATA
5525 *
5526 * returns 1 if valid or 0 otherwise
5527 */
5528static int
5529xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5530 xmlNodePtr elem) {
5531 int ret = 1;
5532 xmlNodePtr cur, child;
5533
Daniel Veillard3e62adb2012-08-09 14:24:02 +08005534 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL) ||
5535 (elem->type != XML_ELEMENT_NODE))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005536 return(0);
5537
5538 child = elem->children;
5539
5540 cur = child;
5541 while (cur != NULL) {
5542 switch (cur->type) {
5543 case XML_ENTITY_REF_NODE:
5544 /*
5545 * Push the current node to be able to roll back
5546 * and process within the entity
5547 */
5548 if ((cur->children != NULL) &&
5549 (cur->children->children != NULL)) {
5550 nodeVPush(ctxt, cur);
5551 cur = cur->children->children;
5552 continue;
5553 }
5554 break;
5555 case XML_COMMENT_NODE:
5556 case XML_PI_NODE:
5557 case XML_TEXT_NODE:
5558 case XML_CDATA_SECTION_NODE:
5559 break;
5560 default:
5561 ret = 0;
5562 goto done;
5563 }
5564 /*
5565 * Switch to next element
5566 */
5567 cur = cur->next;
5568 while (cur == NULL) {
5569 cur = nodeVPop(ctxt);
5570 if (cur == NULL)
5571 break;
5572 cur = cur->next;
5573 }
5574 }
5575done:
5576 ctxt->nodeMax = 0;
5577 ctxt->nodeNr = 0;
5578 if (ctxt->nodeTab != NULL) {
5579 xmlFree(ctxt->nodeTab);
5580 ctxt->nodeTab = NULL;
5581 }
5582 return(ret);
5583}
5584
5585/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005586 * xmlValidateCheckMixed:
5587 * @ctxt: the validation context
5588 * @cont: the mixed content model
5589 * @qname: the qualified name as appearing in the serialization
5590 *
5591 * Check if the given node is part of the content model.
5592 *
5593 * Returns 1 if yes, 0 if no, -1 in case of error
5594 */
5595static int
William M. Brackedb65a72004-02-06 07:36:04 +00005596xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005597 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005598 const xmlChar *name;
5599 int plen;
5600 name = xmlSplitQName3(qname, &plen);
5601
5602 if (name == NULL) {
5603 while (cont != NULL) {
5604 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5605 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5606 return(1);
5607 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5608 (cont->c1 != NULL) &&
5609 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5610 if ((cont->c1->prefix == NULL) &&
5611 (xmlStrEqual(cont->c1->name, qname)))
5612 return(1);
5613 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5614 (cont->c1 == NULL) ||
5615 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005616 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005617 "Internal: MIXED struct corrupted\n",
5618 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005619 break;
5620 }
5621 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005622 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005623 } else {
5624 while (cont != NULL) {
5625 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5626 if ((cont->prefix != NULL) &&
5627 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5628 (xmlStrEqual(cont->name, name)))
5629 return(1);
5630 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5631 (cont->c1 != NULL) &&
5632 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5633 if ((cont->c1->prefix != NULL) &&
5634 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5635 (xmlStrEqual(cont->c1->name, name)))
5636 return(1);
5637 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5638 (cont->c1 == NULL) ||
5639 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005640 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005641 "Internal: MIXED struct corrupted\n",
5642 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005643 break;
5644 }
5645 cont = cont->c2;
5646 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005647 }
5648 return(0);
5649}
5650
5651/**
5652 * xmlValidGetElemDecl:
5653 * @ctxt: the validation context
5654 * @doc: a document instance
5655 * @elem: an element instance
5656 * @extsubset: pointer, (out) indicate if the declaration was found
5657 * in the external subset.
5658 *
5659 * Finds a declaration associated to an element in the document.
5660 *
5661 * returns the pointer to the declaration or NULL if not found.
5662 */
5663static xmlElementPtr
5664xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5665 xmlNodePtr elem, int *extsubset) {
5666 xmlElementPtr elemDecl = NULL;
5667 const xmlChar *prefix = NULL;
5668
Daniel Veillardf8e3db02012-09-11 13:26:36 +08005669 if ((ctxt == NULL) || (doc == NULL) ||
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005670 (elem == NULL) || (elem->name == NULL))
5671 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005672 if (extsubset != NULL)
5673 *extsubset = 0;
5674
5675 /*
5676 * Fetch the declaration for the qualified name
5677 */
5678 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5679 prefix = elem->ns->prefix;
5680
5681 if (prefix != NULL) {
5682 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5683 elem->name, prefix);
5684 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5685 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5686 elem->name, prefix);
5687 if ((elemDecl != NULL) && (extsubset != NULL))
5688 *extsubset = 1;
5689 }
5690 }
5691
5692 /*
5693 * Fetch the declaration for the non qualified name
5694 * This is "non-strict" validation should be done on the
5695 * full QName but in that case being flexible makes sense.
5696 */
5697 if (elemDecl == NULL) {
5698 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5699 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5700 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5701 if ((elemDecl != NULL) && (extsubset != NULL))
5702 *extsubset = 1;
5703 }
5704 }
5705 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005706 xmlErrValidNode(ctxt, elem,
5707 XML_DTD_UNKNOWN_ELEM,
5708 "No declaration for element %s\n",
5709 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005710 }
5711 return(elemDecl);
5712}
5713
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005714#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005715/**
5716 * xmlValidatePushElement:
5717 * @ctxt: the validation context
5718 * @doc: a document instance
5719 * @elem: an element instance
5720 * @qname: the qualified name as appearing in the serialization
5721 *
5722 * Push a new element start on the validation stack.
5723 *
5724 * returns 1 if no validation problem was found or 0 otherwise
5725 */
5726int
5727xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5728 xmlNodePtr elem, const xmlChar *qname) {
5729 int ret = 1;
5730 xmlElementPtr eDecl;
5731 int extsubset = 0;
5732
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005733 if (ctxt == NULL)
5734 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005735/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005736 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5737 xmlValidStatePtr state = ctxt->vstate;
5738 xmlElementPtr elemDecl;
5739
5740 /*
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +02005741 * Check the new element against the content model of the new elem.
Daniel Veillardea7751d2002-12-20 00:16:24 +00005742 */
5743 if (state->elemDecl != NULL) {
5744 elemDecl = state->elemDecl;
5745
5746 switch(elemDecl->etype) {
5747 case XML_ELEMENT_TYPE_UNDEFINED:
5748 ret = 0;
5749 break;
5750 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005751 xmlErrValidNode(ctxt, state->node,
5752 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005753 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005754 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005755 ret = 0;
5756 break;
5757 case XML_ELEMENT_TYPE_ANY:
5758 /* I don't think anything is required then */
5759 break;
5760 case XML_ELEMENT_TYPE_MIXED:
5761 /* simple case of declared as #PCDATA */
5762 if ((elemDecl->content != NULL) &&
5763 (elemDecl->content->type ==
5764 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005765 xmlErrValidNode(ctxt, state->node,
5766 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005767 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005768 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005769 ret = 0;
5770 } else {
5771 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5772 qname);
5773 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005774 xmlErrValidNode(ctxt, state->node,
5775 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005776 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005777 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005778 }
5779 }
5780 break;
5781 case XML_ELEMENT_TYPE_ELEMENT:
5782 /*
5783 * TODO:
5784 * VC: Standalone Document Declaration
5785 * - element types with element content, if white space
5786 * occurs directly within any instance of those types.
5787 */
5788 if (state->exec != NULL) {
5789 ret = xmlRegExecPushString(state->exec, qname, NULL);
5790 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005791 xmlErrValidNode(ctxt, state->node,
5792 XML_DTD_CONTENT_MODEL,
5793 "Element %s content does not follow the DTD, Misplaced %s\n",
5794 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005795 ret = 0;
5796 } else {
5797 ret = 1;
5798 }
5799 }
5800 break;
5801 }
5802 }
5803 }
5804 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5805 vstateVPush(ctxt, eDecl, elem);
5806 return(ret);
5807}
5808
5809/**
5810 * xmlValidatePushCData:
5811 * @ctxt: the validation context
5812 * @data: some character data read
Michael Woodfb27e2c2012-09-28 08:59:33 +02005813 * @len: the length of the data
Daniel Veillardea7751d2002-12-20 00:16:24 +00005814 *
5815 * check the CData parsed for validation in the current stack
5816 *
5817 * returns 1 if no validation problem was found or 0 otherwise
5818 */
5819int
5820xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5821 int ret = 1;
5822
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005823/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005824 if (ctxt == NULL)
5825 return(0);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005826 if (len <= 0)
5827 return(ret);
5828 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5829 xmlValidStatePtr state = ctxt->vstate;
5830 xmlElementPtr elemDecl;
5831
5832 /*
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +02005833 * Check the new element against the content model of the new elem.
Daniel Veillardea7751d2002-12-20 00:16:24 +00005834 */
5835 if (state->elemDecl != NULL) {
5836 elemDecl = state->elemDecl;
5837
5838 switch(elemDecl->etype) {
5839 case XML_ELEMENT_TYPE_UNDEFINED:
5840 ret = 0;
5841 break;
5842 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005843 xmlErrValidNode(ctxt, state->node,
5844 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005845 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005846 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005847 ret = 0;
5848 break;
5849 case XML_ELEMENT_TYPE_ANY:
5850 break;
5851 case XML_ELEMENT_TYPE_MIXED:
5852 break;
5853 case XML_ELEMENT_TYPE_ELEMENT:
5854 if (len > 0) {
5855 int i;
5856
5857 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005858 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005859 xmlErrValidNode(ctxt, state->node,
5860 XML_DTD_CONTENT_MODEL,
5861 "Element %s content does not follow the DTD, Text not allowed\n",
5862 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005863 ret = 0;
5864 goto done;
5865 }
5866 }
5867 /*
5868 * TODO:
5869 * VC: Standalone Document Declaration
5870 * element types with element content, if white space
5871 * occurs directly within any instance of those types.
5872 */
5873 }
5874 break;
5875 }
5876 }
5877 }
5878done:
5879 return(ret);
5880}
5881
5882/**
5883 * xmlValidatePopElement:
5884 * @ctxt: the validation context
5885 * @doc: a document instance
5886 * @elem: an element instance
5887 * @qname: the qualified name as appearing in the serialization
5888 *
5889 * Pop the element end from the validation stack.
5890 *
5891 * returns 1 if no validation problem was found or 0 otherwise
5892 */
5893int
5894xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005895 xmlNodePtr elem ATTRIBUTE_UNUSED,
5896 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005897 int ret = 1;
5898
Daniel Veillardc0be74b2004-11-03 19:16:55 +00005899 if (ctxt == NULL)
5900 return(0);
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005901/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005902 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5903 xmlValidStatePtr state = ctxt->vstate;
5904 xmlElementPtr elemDecl;
5905
5906 /*
Nick Wellnhofer8bbe4502017-06-17 16:15:09 +02005907 * Check the new element against the content model of the new elem.
Daniel Veillardea7751d2002-12-20 00:16:24 +00005908 */
5909 if (state->elemDecl != NULL) {
5910 elemDecl = state->elemDecl;
5911
5912 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5913 if (state->exec != NULL) {
5914 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5915 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005916 xmlErrValidNode(ctxt, state->node,
5917 XML_DTD_CONTENT_MODEL,
5918 "Element %s content does not follow the DTD, Expecting more child\n",
5919 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005920 } else {
5921 /*
5922 * previous validation errors should not generate
5923 * a new one here
5924 */
5925 ret = 1;
5926 }
5927 }
5928 }
5929 }
5930 vstateVPop(ctxt);
5931 }
5932 return(ret);
5933}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005934#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005935
5936/**
Owen Taylor3473f882001-02-23 17:55:21 +00005937 * xmlValidateOneElement:
5938 * @ctxt: the validation context
5939 * @doc: a document instance
5940 * @elem: an element instance
5941 *
5942 * Try to validate a single element and it's attributes,
5943 * basically it does the following checks as described by the
5944 * XML-1.0 recommendation:
5945 * - [ VC: Element Valid ]
5946 * - [ VC: Required Attribute ]
5947 * Then call xmlValidateOneAttribute() for each attribute present.
5948 *
5949 * The ID/IDREF checkings are done separately
5950 *
5951 * returns 1 if valid or 0 otherwise
5952 */
5953
5954int
5955xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5956 xmlNodePtr elem) {
5957 xmlElementPtr elemDecl = NULL;
5958 xmlElementContentPtr cont;
5959 xmlAttributePtr attr;
5960 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005961 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005962 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005963 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005964
5965 CHECK_DTD;
5966
5967 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005968 switch (elem->type) {
5969 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005970 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5971 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005972 return(0);
5973 case XML_TEXT_NODE:
5974 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005975 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5976 "Text element has children !\n",
5977 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005978 return(0);
5979 }
Owen Taylor3473f882001-02-23 17:55:21 +00005980 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005981 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5982 "Text element has namespace !\n",
5983 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005984 return(0);
5985 }
Owen Taylor3473f882001-02-23 17:55:21 +00005986 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005987 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5988 "Text element has no content !\n",
5989 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005990 return(0);
5991 }
5992 return(1);
5993 case XML_XINCLUDE_START:
5994 case XML_XINCLUDE_END:
5995 return(1);
5996 case XML_CDATA_SECTION_NODE:
5997 case XML_ENTITY_REF_NODE:
5998 case XML_PI_NODE:
5999 case XML_COMMENT_NODE:
6000 return(1);
6001 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006002 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6003 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006004 return(0);
6005 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006006 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6007 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006008 return(0);
6009 case XML_DOCUMENT_NODE:
6010 case XML_DOCUMENT_TYPE_NODE:
6011 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006012 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6013 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006014 return(0);
6015 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006016 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6017 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006018 return(0);
6019 case XML_ELEMENT_NODE:
6020 break;
6021 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006022 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6023 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006024 return(0);
6025 }
Owen Taylor3473f882001-02-23 17:55:21 +00006026
6027 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00006028 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00006029 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00006030 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
6031 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006032 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006033
Daniel Veillardea7751d2002-12-20 00:16:24 +00006034 /*
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006035 * If vstateNr is not zero that means continuous validation is
Daniel Veillardea7751d2002-12-20 00:16:24 +00006036 * activated, do not try to check the content model at that level.
6037 */
6038 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006039 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00006040 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00006041 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006042 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
6043 "No declaration for element %s\n",
6044 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00006045 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006046 case XML_ELEMENT_TYPE_EMPTY:
6047 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006048 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00006049 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006050 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006051 ret = 0;
6052 }
6053 break;
6054 case XML_ELEMENT_TYPE_ANY:
6055 /* I don't think anything is required then */
6056 break;
6057 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006058
Daniel Veillard04e2dae2001-07-09 20:07:25 +00006059 /* simple case of declared as #PCDATA */
6060 if ((elemDecl->content != NULL) &&
6061 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
6062 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
6063 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006064 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00006065 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006066 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00006067 }
6068 break;
6069 }
Owen Taylor3473f882001-02-23 17:55:21 +00006070 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00006071 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00006072 while (child != NULL) {
6073 if (child->type == XML_ELEMENT_NODE) {
6074 name = child->name;
6075 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006076 xmlChar fn[50];
6077 xmlChar *fullname;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006078
Daniel Veillardc00cda82003-04-07 10:22:39 +00006079 fullname = xmlBuildQName(child->name, child->ns->prefix,
6080 fn, 50);
6081 if (fullname == NULL)
6082 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006083 cont = elemDecl->content;
6084 while (cont != NULL) {
6085 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006086 if (xmlStrEqual(cont->name, fullname))
6087 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006088 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6089 (cont->c1 != NULL) &&
6090 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00006091 if (xmlStrEqual(cont->c1->name, fullname))
6092 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006093 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6094 (cont->c1 == NULL) ||
6095 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006096 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006097 "Internal: MIXED struct corrupted\n",
6098 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006099 break;
6100 }
6101 cont = cont->c2;
6102 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00006103 if ((fullname != fn) && (fullname != child->name))
6104 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00006105 if (cont != NULL)
6106 goto child_ok;
6107 }
6108 cont = elemDecl->content;
6109 while (cont != NULL) {
6110 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6111 if (xmlStrEqual(cont->name, name)) break;
6112 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6113 (cont->c1 != NULL) &&
6114 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
6115 if (xmlStrEqual(cont->c1->name, name)) break;
6116 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6117 (cont->c1 == NULL) ||
6118 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006119 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006120 "Internal: MIXED struct corrupted\n",
6121 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006122 break;
6123 }
6124 cont = cont->c2;
6125 }
6126 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006127 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006128 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006129 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006130 ret = 0;
6131 }
6132 }
6133child_ok:
6134 child = child->next;
6135 }
6136 break;
6137 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006138 if ((doc->standalone == 1) && (extsubset == 1)) {
6139 /*
6140 * VC: Standalone Document Declaration
6141 * - element types with element content, if white space
6142 * occurs directly within any instance of those types.
6143 */
6144 child = elem->children;
6145 while (child != NULL) {
6146 if (child->type == XML_TEXT_NODE) {
6147 const xmlChar *content = child->content;
6148
William M. Brack76e95df2003-10-18 16:20:14 +00006149 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006150 content++;
6151 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006152 xmlErrValidNode(ctxt, elem,
6153 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006154"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006155 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006156 ret = 0;
6157 break;
6158 }
6159 }
6160 child =child->next;
6161 }
6162 }
Owen Taylor3473f882001-02-23 17:55:21 +00006163 child = elem->children;
6164 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00006165 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00006166 if (tmp <= 0)
6167 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00006168 break;
6169 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00006170 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00006171
6172 /* [ VC: Required Attribute ] */
6173 attr = elemDecl->attributes;
6174 while (attr != NULL) {
6175 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00006176 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006177
Daniel Veillarde4301c82002-02-13 13:32:35 +00006178 if ((attr->prefix == NULL) &&
6179 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6180 xmlNsPtr ns;
6181
6182 ns = elem->nsDef;
6183 while (ns != NULL) {
6184 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00006185 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006186 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00006187 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006188 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6189 xmlNsPtr ns;
6190
6191 ns = elem->nsDef;
6192 while (ns != NULL) {
6193 if (xmlStrEqual(attr->name, ns->prefix))
6194 goto found;
6195 ns = ns->next;
6196 }
6197 } else {
6198 xmlAttrPtr attrib;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006199
Daniel Veillarde4301c82002-02-13 13:32:35 +00006200 attrib = elem->properties;
6201 while (attrib != NULL) {
6202 if (xmlStrEqual(attrib->name, attr->name)) {
6203 if (attr->prefix != NULL) {
6204 xmlNsPtr nameSpace = attrib->ns;
6205
6206 if (nameSpace == NULL)
6207 nameSpace = elem->ns;
6208 /*
6209 * qualified names handling is problematic, having a
6210 * different prefix should be possible but DTDs don't
6211 * allow to define the URI instead of the prefix :-(
6212 */
6213 if (nameSpace == NULL) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006214 if (qualified < 0)
Daniel Veillarde4301c82002-02-13 13:32:35 +00006215 qualified = 0;
6216 } else if (!xmlStrEqual(nameSpace->prefix,
6217 attr->prefix)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006218 if (qualified < 1)
Daniel Veillarde4301c82002-02-13 13:32:35 +00006219 qualified = 1;
6220 } else
6221 goto found;
6222 } else {
6223 /*
6224 * We should allow applications to define namespaces
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006225 * for their application even if the DTD doesn't
Daniel Veillarde4301c82002-02-13 13:32:35 +00006226 * carry one, otherwise, basically we would always
6227 * break.
6228 */
6229 goto found;
6230 }
6231 }
6232 attrib = attrib->next;
6233 }
Owen Taylor3473f882001-02-23 17:55:21 +00006234 }
6235 if (qualified == -1) {
6236 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006237 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006238 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006239 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006240 ret = 0;
6241 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006242 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006243 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00006244 elem->name, attr->prefix,attr->name);
6245 ret = 0;
6246 }
6247 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006248 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006249 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006250 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006251 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006252 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00006253 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006254 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00006255 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00006256 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
6257 /*
6258 * Special tests checking #FIXED namespace declarations
6259 * have the right value since this is not done as an
6260 * attribute checking
6261 */
6262 if ((attr->prefix == NULL) &&
6263 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6264 xmlNsPtr ns;
6265
6266 ns = elem->nsDef;
6267 while (ns != NULL) {
6268 if (ns->prefix == NULL) {
6269 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006270 xmlErrValidNode(ctxt, elem,
6271 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00006272 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006273 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006274 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006275 }
6276 goto found;
6277 }
6278 ns = ns->next;
6279 }
6280 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6281 xmlNsPtr ns;
6282
6283 ns = elem->nsDef;
6284 while (ns != NULL) {
6285 if (xmlStrEqual(attr->name, ns->prefix)) {
6286 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006287 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006288 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006289 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00006290 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00006291 }
6292 goto found;
6293 }
6294 ns = ns->next;
6295 }
6296 }
Owen Taylor3473f882001-02-23 17:55:21 +00006297 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006298found:
Owen Taylor3473f882001-02-23 17:55:21 +00006299 attr = attr->nexth;
6300 }
6301 return(ret);
6302}
6303
6304/**
6305 * xmlValidateRoot:
6306 * @ctxt: the validation context
6307 * @doc: a document instance
6308 *
6309 * Try to validate a the root element
6310 * basically it does the following check as described by the
6311 * XML-1.0 recommendation:
6312 * - [ VC: Root Element Type ]
6313 * it doesn't try to recurse or apply other check to the element
6314 *
6315 * returns 1 if valid or 0 otherwise
6316 */
6317
6318int
6319xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6320 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00006321 int ret;
6322
Owen Taylor3473f882001-02-23 17:55:21 +00006323 if (doc == NULL) return(0);
6324
6325 root = xmlDocGetRootElement(doc);
6326 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006327 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6328 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006329 return(0);
6330 }
6331
6332 /*
6333 * When doing post validation against a separate DTD, those may
6334 * no internal subset has been generated
6335 */
6336 if ((doc->intSubset != NULL) &&
6337 (doc->intSubset->name != NULL)) {
6338 /*
6339 * Check first the document root against the NQName
6340 */
6341 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6342 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006343 xmlChar fn[50];
6344 xmlChar *fullname;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006345
Daniel Veillardc00cda82003-04-07 10:22:39 +00006346 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6347 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006348 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006349 return(0);
6350 }
6351 ret = xmlStrEqual(doc->intSubset->name, fullname);
6352 if ((fullname != fn) && (fullname != root->name))
6353 xmlFree(fullname);
6354 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006355 goto name_ok;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006356 }
Owen Taylor3473f882001-02-23 17:55:21 +00006357 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6358 (xmlStrEqual(root->name, BAD_CAST "html")))
6359 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006360 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6361 "root and DTD name do not match '%s' and '%s'\n",
6362 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006363 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006364 }
6365 }
6366name_ok:
6367 return(1);
6368}
6369
6370
6371/**
6372 * xmlValidateElement:
6373 * @ctxt: the validation context
6374 * @doc: a document instance
6375 * @elem: an element instance
6376 *
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006377 * Try to validate the subtree under an element
Owen Taylor3473f882001-02-23 17:55:21 +00006378 *
6379 * returns 1 if valid or 0 otherwise
6380 */
6381
6382int
6383xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6384 xmlNodePtr child;
6385 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006386 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006387 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006388 int ret = 1;
6389
6390 if (elem == NULL) return(0);
6391
6392 /*
6393 * XInclude elements were added after parsing in the infoset,
6394 * they don't really mean anything validation wise.
6395 */
6396 if ((elem->type == XML_XINCLUDE_START) ||
Daniel Veillard3e62adb2012-08-09 14:24:02 +08006397 (elem->type == XML_XINCLUDE_END) ||
6398 (elem->type == XML_NAMESPACE_DECL))
Owen Taylor3473f882001-02-23 17:55:21 +00006399 return(1);
6400
6401 CHECK_DTD;
6402
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006403 /*
6404 * Entities references have to be handled separately
6405 */
6406 if (elem->type == XML_ENTITY_REF_NODE) {
6407 return(1);
6408 }
6409
Owen Taylor3473f882001-02-23 17:55:21 +00006410 ret &= xmlValidateOneElement(ctxt, doc, elem);
Daniel Veillard8874b942005-08-25 13:19:21 +00006411 if (elem->type == XML_ELEMENT_NODE) {
6412 attr = elem->properties;
6413 while (attr != NULL) {
6414 value = xmlNodeListGetString(doc, attr->children, 0);
6415 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6416 if (value != NULL)
6417 xmlFree((char *)value);
6418 attr= attr->next;
6419 }
6420 ns = elem->nsDef;
6421 while (ns != NULL) {
6422 if (elem->ns == NULL)
6423 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6424 ns, ns->href);
6425 else
6426 ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6427 elem->ns->prefix, ns, ns->href);
6428 ns = ns->next;
6429 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006430 }
Owen Taylor3473f882001-02-23 17:55:21 +00006431 child = elem->children;
6432 while (child != NULL) {
6433 ret &= xmlValidateElement(ctxt, doc, child);
6434 child = child->next;
6435 }
6436
6437 return(ret);
6438}
6439
Daniel Veillard8730c562001-02-26 10:49:57 +00006440/**
6441 * xmlValidateRef:
6442 * @ref: A reference to be validated
6443 * @ctxt: Validation context
6444 * @name: Name of ID we are searching for
6445 *
6446 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006447static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006448xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006449 const xmlChar *name) {
6450 xmlAttrPtr id;
6451 xmlAttrPtr attr;
6452
6453 if (ref == NULL)
6454 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006455 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006456 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006457 attr = ref->attr;
6458 if (attr == NULL) {
6459 xmlChar *dup, *str = NULL, *cur, save;
6460
6461 dup = xmlStrdup(name);
6462 if (dup == NULL) {
6463 ctxt->valid = 0;
6464 return;
6465 }
6466 cur = dup;
6467 while (*cur != 0) {
6468 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006469 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006470 save = *cur;
6471 *cur = 0;
6472 id = xmlGetID(ctxt->doc, str);
6473 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006474 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006475 "attribute %s line %d references an unknown ID \"%s\"\n",
6476 ref->name, ref->lineno, str);
6477 ctxt->valid = 0;
6478 }
6479 if (save == 0)
6480 break;
6481 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006482 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006483 }
6484 xmlFree(dup);
6485 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006486 id = xmlGetID(ctxt->doc, name);
6487 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006488 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006489 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006490 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006491 ctxt->valid = 0;
6492 }
6493 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6494 xmlChar *dup, *str = NULL, *cur, save;
6495
6496 dup = xmlStrdup(name);
6497 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006498 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006499 ctxt->valid = 0;
6500 return;
6501 }
6502 cur = dup;
6503 while (*cur != 0) {
6504 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006505 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006506 save = *cur;
6507 *cur = 0;
6508 id = xmlGetID(ctxt->doc, str);
6509 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006510 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006511 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006512 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006513 ctxt->valid = 0;
6514 }
6515 if (save == 0)
6516 break;
6517 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006518 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006519 }
6520 xmlFree(dup);
6521 }
6522}
6523
6524/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006525 * xmlWalkValidateList:
6526 * @data: Contents of current link
6527 * @user: Value supplied by the user
6528 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006529 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006530 */
6531static int
6532xmlWalkValidateList(const void *data, const void *user)
6533{
6534 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6535 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6536 return 1;
6537}
6538
6539/**
6540 * xmlValidateCheckRefCallback:
6541 * @ref_list: List of references
6542 * @ctxt: Validation context
6543 * @name: Name of ID we are searching for
6544 *
6545 */
6546static void
6547xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6548 const xmlChar *name) {
6549 xmlValidateMemo memo;
6550
6551 if (ref_list == NULL)
6552 return;
6553 memo.ctxt = ctxt;
6554 memo.name = name;
6555
6556 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006557
Daniel Veillard8730c562001-02-26 10:49:57 +00006558}
6559
6560/**
Owen Taylor3473f882001-02-23 17:55:21 +00006561 * xmlValidateDocumentFinal:
6562 * @ctxt: the validation context
6563 * @doc: a document instance
6564 *
6565 * Does the final step for the document validation once all the
6566 * incremental validation steps have been completed
6567 *
6568 * basically it does the following checks described by the XML Rec
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006569 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006570 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006571 *
6572 * returns 1 if valid or 0 otherwise
6573 */
6574
6575int
6576xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6577 xmlRefTablePtr table;
Daniel Veillardcb3549e2011-11-11 11:25:07 +08006578 unsigned int save;
Owen Taylor3473f882001-02-23 17:55:21 +00006579
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006580 if (ctxt == NULL)
6581 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006582 if (doc == NULL) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006583 xmlErrValid(ctxt, XML_DTD_NO_DOC,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006584 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006585 return(0);
6586 }
6587
Daniel Veillardcb3549e2011-11-11 11:25:07 +08006588 /* trick to get correct line id report */
6589 save = ctxt->finishDtd;
6590 ctxt->finishDtd = 0;
6591
Owen Taylor3473f882001-02-23 17:55:21 +00006592 /*
6593 * Check all the NOTATION/NOTATIONS attributes
6594 */
6595 /*
6596 * Check all the ENTITY/ENTITIES attributes definition for validity
6597 */
6598 /*
6599 * Check all the IDREF/IDREFS attributes definition for validity
6600 */
6601 table = (xmlRefTablePtr) doc->refs;
6602 ctxt->doc = doc;
6603 ctxt->valid = 1;
6604 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
Daniel Veillardcb3549e2011-11-11 11:25:07 +08006605
6606 ctxt->finishDtd = save;
Owen Taylor3473f882001-02-23 17:55:21 +00006607 return(ctxt->valid);
6608}
6609
6610/**
6611 * xmlValidateDtd:
6612 * @ctxt: the validation context
6613 * @doc: a document instance
6614 * @dtd: a dtd instance
6615 *
6616 * Try to validate the document against the dtd instance
6617 *
William M. Brack367df6e2004-10-23 18:14:36 +00006618 * Basically it does check all the definitions in the DtD.
6619 * Note the the internal subset (if present) is de-coupled
6620 * (i.e. not used), which could give problems if ID or IDREF
6621 * is present.
Owen Taylor3473f882001-02-23 17:55:21 +00006622 *
6623 * returns 1 if valid or 0 otherwise
6624 */
6625
6626int
6627xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6628 int ret;
William M. Brack367df6e2004-10-23 18:14:36 +00006629 xmlDtdPtr oldExt, oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006630 xmlNodePtr root;
6631
6632 if (dtd == NULL) return(0);
6633 if (doc == NULL) return(0);
6634 oldExt = doc->extSubset;
William M. Brack367df6e2004-10-23 18:14:36 +00006635 oldInt = doc->intSubset;
Owen Taylor3473f882001-02-23 17:55:21 +00006636 doc->extSubset = dtd;
William M. Brack367df6e2004-10-23 18:14:36 +00006637 doc->intSubset = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00006638 ret = xmlValidateRoot(ctxt, doc);
6639 if (ret == 0) {
6640 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006641 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006642 return(ret);
6643 }
6644 if (doc->ids != NULL) {
6645 xmlFreeIDTable(doc->ids);
6646 doc->ids = NULL;
6647 }
6648 if (doc->refs != NULL) {
6649 xmlFreeRefTable(doc->refs);
6650 doc->refs = NULL;
6651 }
6652 root = xmlDocGetRootElement(doc);
6653 ret = xmlValidateElement(ctxt, doc, root);
6654 ret &= xmlValidateDocumentFinal(ctxt, doc);
6655 doc->extSubset = oldExt;
William M. Brack367df6e2004-10-23 18:14:36 +00006656 doc->intSubset = oldInt;
Owen Taylor3473f882001-02-23 17:55:21 +00006657 return(ret);
6658}
6659
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006660static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006661xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6662 const xmlChar *name ATTRIBUTE_UNUSED) {
6663 if (cur == NULL)
6664 return;
6665 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6666 xmlChar *notation = cur->content;
6667
Daniel Veillard878eab02002-02-19 13:46:09 +00006668 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006669 int ret;
6670
6671 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6672 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006673 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006674 }
6675 }
6676 }
6677}
6678
6679static void
Owen Taylor3473f882001-02-23 17:55:21 +00006680xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006681 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006682 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006683 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006684 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006685
Owen Taylor3473f882001-02-23 17:55:21 +00006686 if (cur == NULL)
6687 return;
6688 switch (cur->atype) {
6689 case XML_ATTRIBUTE_CDATA:
6690 case XML_ATTRIBUTE_ID:
6691 case XML_ATTRIBUTE_IDREF :
6692 case XML_ATTRIBUTE_IDREFS:
6693 case XML_ATTRIBUTE_NMTOKEN:
6694 case XML_ATTRIBUTE_NMTOKENS:
6695 case XML_ATTRIBUTE_ENUMERATION:
6696 break;
6697 case XML_ATTRIBUTE_ENTITY:
6698 case XML_ATTRIBUTE_ENTITIES:
6699 case XML_ATTRIBUTE_NOTATION:
6700 if (cur->defaultValue != NULL) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006701
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006702 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6703 cur->atype, cur->defaultValue);
6704 if ((ret == 0) && (ctxt->valid == 1))
6705 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006706 }
6707 if (cur->tree != NULL) {
6708 xmlEnumerationPtr tree = cur->tree;
6709 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006710 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006711 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006712 if ((ret == 0) && (ctxt->valid == 1))
6713 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006714 tree = tree->next;
6715 }
6716 }
6717 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006718 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6719 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006720 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006721 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006722 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006723 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006724 return;
6725 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006726
6727 if (doc != NULL)
6728 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6729 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006730 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006731 if ((elem == NULL) && (cur->parent != NULL) &&
6732 (cur->parent->type == XML_DTD_NODE))
6733 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006734 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006735 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006736 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006737 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006738 return;
6739 }
6740 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006741 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006742 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006743 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006744 ctxt->valid = 0;
6745 }
6746 }
Owen Taylor3473f882001-02-23 17:55:21 +00006747}
6748
6749/**
6750 * xmlValidateDtdFinal:
6751 * @ctxt: the validation context
6752 * @doc: a document instance
6753 *
6754 * Does the final step for the dtds validation once all the
6755 * subsets have been parsed
6756 *
6757 * basically it does the following checks described by the XML Rec
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006758 * - check that ENTITY and ENTITIES type attributes default or
Owen Taylor3473f882001-02-23 17:55:21 +00006759 * possible values matches one of the defined entities.
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006760 * - check that NOTATION type attributes default or
Owen Taylor3473f882001-02-23 17:55:21 +00006761 * possible values matches one of the defined notations.
6762 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006763 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006764 */
6765
6766int
6767xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006768 xmlDtdPtr dtd;
6769 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006770 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006771
Daniel Veillard2cba4152008-08-27 11:45:41 +00006772 if ((doc == NULL) || (ctxt == NULL)) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006773 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6774 return(0);
6775 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006776 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006777 dtd = doc->intSubset;
6778 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6779 table = (xmlAttributeTablePtr) dtd->attributes;
6780 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006781 }
6782 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006783 entities = (xmlEntitiesTablePtr) dtd->entities;
6784 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6785 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006786 }
6787 dtd = doc->extSubset;
6788 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6789 table = (xmlAttributeTablePtr) dtd->attributes;
6790 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006791 }
6792 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006793 entities = (xmlEntitiesTablePtr) dtd->entities;
6794 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6795 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006796 }
6797 return(ctxt->valid);
6798}
6799
6800/**
6801 * xmlValidateDocument:
6802 * @ctxt: the validation context
6803 * @doc: a document instance
6804 *
6805 * Try to validate the document instance
6806 *
6807 * basically it does the all the checks described by the XML Rec
6808 * i.e. validates the internal and external subset (if present)
6809 * and validate the document tree.
6810 *
6811 * returns 1 if valid or 0 otherwise
6812 */
6813
6814int
6815xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6816 int ret;
6817 xmlNodePtr root;
6818
Daniel Veillardc0be74b2004-11-03 19:16:55 +00006819 if (doc == NULL)
6820 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006821 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006822 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6823 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006824 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006825 }
Owen Taylor3473f882001-02-23 17:55:21 +00006826 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6827 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
William M. Brack8c22f9f2004-08-06 16:23:27 +00006828 xmlChar *sysID;
6829 if (doc->intSubset->SystemID != NULL) {
William M. Brackbebe7302004-08-05 06:46:47 +00006830 sysID = xmlBuildURI(doc->intSubset->SystemID,
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006831 doc->URL);
William M. Brack8c22f9f2004-08-06 16:23:27 +00006832 if (sysID == NULL) {
6833 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6834 "Could not build URI for external subset \"%s\"\n",
6835 (const char *) doc->intSubset->SystemID);
6836 return 0;
6837 }
6838 } else
William M. Brackbebe7302004-08-05 06:46:47 +00006839 sysID = NULL;
William M. Brack8c22f9f2004-08-06 16:23:27 +00006840 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
William M. Brackbebe7302004-08-05 06:46:47 +00006841 (const xmlChar *)sysID);
William M. Brackbebe7302004-08-05 06:46:47 +00006842 if (sysID != NULL)
6843 xmlFree(sysID);
Owen Taylor3473f882001-02-23 17:55:21 +00006844 if (doc->extSubset == NULL) {
6845 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006846 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006847 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006848 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006849 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006850 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006851 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006852 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006853 }
6854 return(0);
6855 }
6856 }
6857
6858 if (doc->ids != NULL) {
6859 xmlFreeIDTable(doc->ids);
6860 doc->ids = NULL;
6861 }
6862 if (doc->refs != NULL) {
6863 xmlFreeRefTable(doc->refs);
6864 doc->refs = NULL;
6865 }
6866 ret = xmlValidateDtdFinal(ctxt, doc);
6867 if (!xmlValidateRoot(ctxt, doc)) return(0);
6868
6869 root = xmlDocGetRootElement(doc);
6870 ret &= xmlValidateElement(ctxt, doc, root);
6871 ret &= xmlValidateDocumentFinal(ctxt, doc);
6872 return(ret);
6873}
6874
Owen Taylor3473f882001-02-23 17:55:21 +00006875/************************************************************************
6876 * *
6877 * Routines for dynamic validation editing *
6878 * *
6879 ************************************************************************/
6880
6881/**
6882 * xmlValidGetPotentialChildren:
6883 * @ctree: an element content tree
Daniel Veillard7802ba52005-10-27 11:56:20 +00006884 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006885 * @len: a pointer to the number of element in the list
6886 * @max: the size of the array
6887 *
6888 * Build/extend a list of potential children allowed by the content tree
6889 *
6890 * returns the number of element in the list, or -1 in case of error.
6891 */
6892
6893int
Daniel Veillard7802ba52005-10-27 11:56:20 +00006894xmlValidGetPotentialChildren(xmlElementContent *ctree,
6895 const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006896 int *len, int max) {
6897 int i;
6898
Daniel Veillard7802ba52005-10-27 11:56:20 +00006899 if ((ctree == NULL) || (names == NULL) || (len == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006900 return(-1);
6901 if (*len >= max) return(*len);
6902
6903 switch (ctree->type) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006904 case XML_ELEMENT_CONTENT_PCDATA:
Owen Taylor3473f882001-02-23 17:55:21 +00006905 for (i = 0; i < *len;i++)
Daniel Veillard7802ba52005-10-27 11:56:20 +00006906 if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
6907 names[(*len)++] = BAD_CAST "#PCDATA";
Owen Taylor3473f882001-02-23 17:55:21 +00006908 break;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006909 case XML_ELEMENT_CONTENT_ELEMENT:
Owen Taylor3473f882001-02-23 17:55:21 +00006910 for (i = 0; i < *len;i++)
Daniel Veillard7802ba52005-10-27 11:56:20 +00006911 if (xmlStrEqual(ctree->name, names[i])) return(*len);
6912 names[(*len)++] = ctree->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006913 break;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006914 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard7802ba52005-10-27 11:56:20 +00006915 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6916 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
Owen Taylor3473f882001-02-23 17:55:21 +00006917 break;
6918 case XML_ELEMENT_CONTENT_OR:
Daniel Veillard7802ba52005-10-27 11:56:20 +00006919 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6920 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
Owen Taylor3473f882001-02-23 17:55:21 +00006921 break;
6922 }
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006923
Owen Taylor3473f882001-02-23 17:55:21 +00006924 return(*len);
6925}
6926
William M. Brack9333cc22004-06-24 08:33:40 +00006927/*
6928 * Dummy function to suppress messages while we try out valid elements
6929 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00006930static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
William M. Brack9333cc22004-06-24 08:33:40 +00006931 const char *msg ATTRIBUTE_UNUSED, ...) {
6932 return;
6933}
6934
Owen Taylor3473f882001-02-23 17:55:21 +00006935/**
6936 * xmlValidGetValidElements:
6937 * @prev: an element to insert after
6938 * @next: an element to insert next
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006939 * @names: an array to store the list of child names
Owen Taylor3473f882001-02-23 17:55:21 +00006940 * @max: the size of the array
6941 *
6942 * This function returns the list of authorized children to insert
6943 * within an existing tree while respecting the validity constraints
6944 * forced by the Dtd. The insertion point is defined using @prev and
6945 * @next in the following ways:
6946 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6947 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6948 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6949 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6950 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6951 *
6952 * pointers to the element names are inserted at the beginning of the array
6953 * and do not need to be freed.
6954 *
6955 * returns the number of element in the list, or -1 in case of error. If
6956 * the function returns the value @max the caller is invited to grow the
6957 * receiving array and retry.
6958 */
6959
6960int
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006961xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
Owen Taylor3473f882001-02-23 17:55:21 +00006962 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006963 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006964 int nb_valid_elements = 0;
Daniel Veillarde18bce02014-02-06 10:47:20 +01006965 const xmlChar *elements[256]={0};
Owen Taylor3473f882001-02-23 17:55:21 +00006966 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006967 const xmlChar *name;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006968
Owen Taylor3473f882001-02-23 17:55:21 +00006969 xmlNode *ref_node;
6970 xmlNode *parent;
6971 xmlNode *test_node;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006972
Owen Taylor3473f882001-02-23 17:55:21 +00006973 xmlNode *prev_next;
6974 xmlNode *next_prev;
6975 xmlNode *parent_childs;
6976 xmlNode *parent_last;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08006977
Owen Taylor3473f882001-02-23 17:55:21 +00006978 xmlElement *element_desc;
6979
6980 if (prev == NULL && next == NULL)
6981 return(-1);
6982
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00006983 if (names == NULL) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00006984 if (max <= 0) return(-1);
6985
William M. Brack9333cc22004-06-24 08:33:40 +00006986 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6987 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6988
Owen Taylor3473f882001-02-23 17:55:21 +00006989 nb_valid_elements = 0;
6990 ref_node = prev ? prev : next;
6991 parent = ref_node->parent;
6992
6993 /*
6994 * Retrieves the parent element declaration
6995 */
6996 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6997 parent->name);
6998 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6999 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
7000 parent->name);
7001 if (element_desc == NULL) return(-1);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007002
Owen Taylor3473f882001-02-23 17:55:21 +00007003 /*
7004 * Do a backup of the current tree structure
7005 */
7006 prev_next = prev ? prev->next : NULL;
7007 next_prev = next ? next->prev : NULL;
7008 parent_childs = parent->children;
7009 parent_last = parent->last;
7010
7011 /*
7012 * Creates a dummy node and insert it into the tree
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007013 */
Daniel Veillard95ddcd32004-10-26 21:53:55 +00007014 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
Gaurav Gupta658b86c2014-08-07 11:19:03 +08007015 if (test_node == NULL)
7016 return(-1);
7017
Owen Taylor3473f882001-02-23 17:55:21 +00007018 test_node->parent = parent;
7019 test_node->prev = prev;
7020 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00007021 name = test_node->name;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007022
Owen Taylor3473f882001-02-23 17:55:21 +00007023 if (prev) prev->next = test_node;
7024 else parent->children = test_node;
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007025
Owen Taylor3473f882001-02-23 17:55:21 +00007026 if (next) next->prev = test_node;
7027 else parent->last = test_node;
7028
7029 /*
7030 * Insert each potential child node and check if the parent is
7031 * still valid
7032 */
7033 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
7034 elements, &nb_elements, 256);
Daniel Veillardf8e3db02012-09-11 13:26:36 +08007035
Owen Taylor3473f882001-02-23 17:55:21 +00007036 for (i = 0;i < nb_elements;i++) {
7037 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00007038 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007039 int j;
7040
7041 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillardaecc0dc2004-05-08 02:32:07 +00007042 if (xmlStrEqual(elements[i], names[j])) break;
7043 names[nb_valid_elements++] = elements[i];
Owen Taylor3473f882001-02-23 17:55:21 +00007044 if (nb_valid_elements >= max) break;
7045 }
7046 }
7047
7048 /*
7049 * Restore the tree structure
7050 */
7051 if (prev) prev->next = prev_next;
7052 if (next) next->prev = next_prev;
7053 parent->children = parent_childs;
7054 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00007055
7056 /*
7057 * Free up the dummy node
7058 */
7059 test_node->name = name;
7060 xmlFreeNode(test_node);
7061
Owen Taylor3473f882001-02-23 17:55:21 +00007062 return(nb_valid_elements);
7063}
Daniel Veillard4432df22003-09-28 18:58:27 +00007064#endif /* LIBXML_VALID_ENABLED */
7065
Daniel Veillard5d4644e2005-04-01 13:11:58 +00007066#define bottom_valid
7067#include "elfgcchack.h"