blob: 351f03ac628374e59b27b418a87d01dc115c4101 [file] [log] [blame]
Daniel Veillard6eadf632003-01-23 18:29:16 +00001/*
2 * relaxng.c : implementation of the Relax-NG handling and validity checking
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel Veillard <veillard@redhat.com>
7 */
8
Daniel Veillardd41f4f42003-01-29 21:07:52 +00009/**
10 * TODO:
Daniel Veillardf4b4f982003-02-13 11:02:08 +000011 * - add support for DTD compatibility spec
12 * http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
Daniel Veillardac297932003-04-17 12:55:35 +000013 * - report better mem allocations pbms at runtime and abort immediately.
Daniel Veillardd41f4f42003-01-29 21:07:52 +000014 */
15
Daniel Veillard6eadf632003-01-23 18:29:16 +000016#define IN_LIBXML
17#include "libxml.h"
18
19#ifdef LIBXML_SCHEMAS_ENABLED
20
21#include <string.h>
22#include <stdio.h>
23#include <libxml/xmlmemory.h>
24#include <libxml/parser.h>
25#include <libxml/parserInternals.h>
26#include <libxml/hash.h>
27#include <libxml/uri.h>
28
29#include <libxml/relaxng.h>
30
31#include <libxml/xmlschemastypes.h>
32#include <libxml/xmlautomata.h>
33#include <libxml/xmlregexp.h>
Daniel Veillardc6e997c2003-01-27 12:35:42 +000034#include <libxml/xmlschemastypes.h>
Daniel Veillard6eadf632003-01-23 18:29:16 +000035
36/*
37 * The Relax-NG namespace
38 */
39static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
40 "http://relaxng.org/ns/structure/1.0";
41
42#define IS_RELAXNG(node, type) \
43 ((node != NULL) && (node->ns != NULL) && \
44 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
45 (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
46
47
Daniel Veillard23a47d62008-06-25 04:11:24 +000048#if 0
Daniel Veillard87254c82006-02-19 15:27:17 +000049#define DEBUG 1
Daniel Veillard4c004142003-10-07 11:33:24 +000050
Daniel Veillard87254c82006-02-19 15:27:17 +000051#define DEBUG_GRAMMAR 1
Daniel Veillard4c004142003-10-07 11:33:24 +000052
Daniel Veillard87254c82006-02-19 15:27:17 +000053#define DEBUG_CONTENT 1
Daniel Veillard4c004142003-10-07 11:33:24 +000054
Daniel Veillard87254c82006-02-19 15:27:17 +000055#define DEBUG_TYPE 1
Daniel Veillard4c004142003-10-07 11:33:24 +000056
Daniel Veillard87254c82006-02-19 15:27:17 +000057#define DEBUG_VALID 1
Daniel Veillard4c004142003-10-07 11:33:24 +000058
Daniel Veillard87254c82006-02-19 15:27:17 +000059#define DEBUG_INTERLEAVE 1
Daniel Veillard4c004142003-10-07 11:33:24 +000060
Daniel Veillard87254c82006-02-19 15:27:17 +000061#define DEBUG_LIST 1
Daniel Veillard4c004142003-10-07 11:33:24 +000062
Daniel Veillard87254c82006-02-19 15:27:17 +000063#define DEBUG_INCLUDE 1
Daniel Veillard4c004142003-10-07 11:33:24 +000064
Daniel Veillard87254c82006-02-19 15:27:17 +000065#define DEBUG_ERROR 1
Daniel Veillard4c004142003-10-07 11:33:24 +000066
Daniel Veillard87254c82006-02-19 15:27:17 +000067#define DEBUG_COMPILE 1
Daniel Veillard4c004142003-10-07 11:33:24 +000068
Daniel Veillard87254c82006-02-19 15:27:17 +000069#define DEBUG_PROGRESSIVE 1
70#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +000071
Daniel Veillard5f1946a2003-03-31 16:38:16 +000072#define MAX_ERROR 5
73
Daniel Veillard6eadf632003-01-23 18:29:16 +000074#define TODO \
75 xmlGenericError(xmlGenericErrorContext, \
76 "Unimplemented block at %s:%d\n", \
77 __FILE__, __LINE__);
78
79typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
80typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
81
82typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
83typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
84
Daniel Veillardd41f4f42003-01-29 21:07:52 +000085typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
86typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
87
Daniel Veillarda9d912d2003-02-01 17:43:10 +000088typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
89typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
90
Daniel Veillard6eadf632003-01-23 18:29:16 +000091typedef enum {
Daniel Veillard4c004142003-10-07 11:33:24 +000092 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
93 XML_RELAXNG_COMBINE_CHOICE, /* choice */
94 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
Daniel Veillard6eadf632003-01-23 18:29:16 +000095} xmlRelaxNGCombine;
96
Daniel Veillard4c5cf702003-02-21 15:40:34 +000097typedef enum {
98 XML_RELAXNG_CONTENT_ERROR = -1,
99 XML_RELAXNG_CONTENT_EMPTY = 0,
100 XML_RELAXNG_CONTENT_SIMPLE,
101 XML_RELAXNG_CONTENT_COMPLEX
102} xmlRelaxNGContentType;
103
Daniel Veillard6eadf632003-01-23 18:29:16 +0000104typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
105typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
106
107struct _xmlRelaxNGGrammar {
Daniel Veillard4c004142003-10-07 11:33:24 +0000108 xmlRelaxNGGrammarPtr parent; /* the parent grammar if any */
109 xmlRelaxNGGrammarPtr children; /* the children grammar if any */
110 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
111 xmlRelaxNGDefinePtr start; /* <start> content */
112 xmlRelaxNGCombine combine; /* the default combine value */
113 xmlRelaxNGDefinePtr startList; /* list of <start> definitions */
114 xmlHashTablePtr defs; /* define* */
115 xmlHashTablePtr refs; /* references */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000116};
117
118
Daniel Veillard6eadf632003-01-23 18:29:16 +0000119typedef enum {
Daniel Veillard4c004142003-10-07 11:33:24 +0000120 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
121 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000122 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard4c004142003-10-07 11:33:24 +0000123 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
124 XML_RELAXNG_TEXT, /* textual content */
125 XML_RELAXNG_ELEMENT, /* an element */
126 XML_RELAXNG_DATATYPE, /* extenal data type definition */
127 XML_RELAXNG_PARAM, /* extenal data type parameter */
128 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
129 XML_RELAXNG_LIST, /* a list of patterns */
130 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
131 XML_RELAXNG_DEF, /* a definition */
132 XML_RELAXNG_REF, /* reference to a definition */
133 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
134 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
135 XML_RELAXNG_OPTIONAL, /* optional patterns */
136 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
137 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
138 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
139 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
140 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
141 XML_RELAXNG_START /* Used to keep track of starts on grammars */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000142} xmlRelaxNGType;
143
Daniel Veillard52b48c72003-04-13 19:53:42 +0000144#define IS_NULLABLE (1 << 0)
145#define IS_NOT_NULLABLE (1 << 1)
146#define IS_INDETERMINIST (1 << 2)
147#define IS_MIXED (1 << 3)
148#define IS_TRIABLE (1 << 4)
149#define IS_PROCESSED (1 << 5)
150#define IS_COMPILABLE (1 << 6)
151#define IS_NOT_COMPILABLE (1 << 7)
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000152
Daniel Veillard6eadf632003-01-23 18:29:16 +0000153struct _xmlRelaxNGDefine {
Daniel Veillard4c004142003-10-07 11:33:24 +0000154 xmlRelaxNGType type; /* the type of definition */
155 xmlNodePtr node; /* the node in the source */
156 xmlChar *name; /* the element local name if present */
157 xmlChar *ns; /* the namespace local name if present */
158 xmlChar *value; /* value when available */
159 void *data; /* data lib or specific pointer */
160 xmlRelaxNGDefinePtr content; /* the expected content */
161 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
162 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
163 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
164 xmlRelaxNGDefinePtr nameClass; /* the nameClass definition if any */
165 xmlRelaxNGDefinePtr nextHash; /* next define in defs/refs hash tables */
166 short depth; /* used for the cycle detection */
167 short dflags; /* define related flags */
168 xmlRegexpPtr contModel; /* a compiled content model if available */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000169};
170
171/**
172 * _xmlRelaxNG:
173 *
174 * A RelaxNGs definition
175 */
176struct _xmlRelaxNG {
Daniel Veillard4c004142003-10-07 11:33:24 +0000177 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000178 xmlRelaxNGGrammarPtr topgrammar;
179 xmlDocPtr doc;
180
Daniel Veillard4c004142003-10-07 11:33:24 +0000181 int idref; /* requires idref checking */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000182
Daniel Veillard4c004142003-10-07 11:33:24 +0000183 xmlHashTablePtr defs; /* define */
184 xmlHashTablePtr refs; /* references */
185 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
186 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
187 int defNr; /* number of defines used */
188 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000189
Daniel Veillard6eadf632003-01-23 18:29:16 +0000190};
191
Daniel Veillard77648bb2003-02-20 15:03:22 +0000192#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
193#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
194#define XML_RELAXNG_IN_LIST (1 << 2)
195#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
196#define XML_RELAXNG_IN_START (1 << 4)
197#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
198#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
199#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000200#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
201#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000202
203struct _xmlRelaxNGParserCtxt {
Daniel Veillard4c004142003-10-07 11:33:24 +0000204 void *userData; /* user specific data block */
205 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
206 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000207 xmlStructuredErrorFunc serror;
Daniel Veillard42f12e92003-03-07 18:32:59 +0000208 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000209
Daniel Veillard4c004142003-10-07 11:33:24 +0000210 xmlRelaxNGPtr schema; /* The schema in use */
211 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
212 xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */
213 int flags; /* parser flags */
214 int nbErrors; /* number of errors at parse time */
215 int nbWarnings; /* number of warnings at parse time */
216 const xmlChar *define; /* the current define scope */
217 xmlRelaxNGDefinePtr def; /* the current define */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000218
Daniel Veillard4c004142003-10-07 11:33:24 +0000219 int nbInterleaves;
220 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000221
Daniel Veillard4c004142003-10-07 11:33:24 +0000222 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
223 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
224 xmlChar *URL;
225 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000226
Daniel Veillard4c004142003-10-07 11:33:24 +0000227 int defNr; /* number of defines used */
228 int defMax; /* number of defines aloocated */
229 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
Daniel Veillard419a7682003-02-03 23:22:49 +0000230
Daniel Veillard4c004142003-10-07 11:33:24 +0000231 const char *buffer;
232 int size;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000233
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000234 /* the document stack */
Daniel Veillard4c004142003-10-07 11:33:24 +0000235 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
236 int docNr; /* Depth of the parsing stack */
237 int docMax; /* Max depth of the parsing stack */
238 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000239
240 /* the include stack */
Daniel Veillard4c004142003-10-07 11:33:24 +0000241 xmlRelaxNGIncludePtr inc; /* Current parsed include */
242 int incNr; /* Depth of the include parsing stack */
243 int incMax; /* Max depth of the parsing stack */
244 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000245
Daniel Veillard4c004142003-10-07 11:33:24 +0000246 int idref; /* requires idref checking */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000247
248 /* used to compile content models */
Daniel Veillard4c004142003-10-07 11:33:24 +0000249 xmlAutomataPtr am; /* the automata */
250 xmlAutomataStatePtr state; /* used to build the automata */
Daniel Veillard03c2f0a2004-01-25 19:54:59 +0000251
252 int crng; /* compact syntax and other flags */
Daniel Veillard42595322004-11-08 10:52:06 +0000253 int freedoc; /* need to free the document */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000254};
255
256#define FLAGS_IGNORABLE 1
257#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000258#define FLAGS_MIXED_CONTENT 4
Daniel Veillardb30ca312005-09-04 13:50:03 +0000259#define FLAGS_NOERROR 8
Daniel Veillard6eadf632003-01-23 18:29:16 +0000260
261/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000262 * xmlRelaxNGInterleaveGroup:
263 *
264 * A RelaxNGs partition set associated to lists of definitions
265 */
266typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
267typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
268struct _xmlRelaxNGInterleaveGroup {
Daniel Veillard4c004142003-10-07 11:33:24 +0000269 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
270 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
271 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000272};
273
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000274#define IS_DETERMINIST 1
275#define IS_NEEDCHECK 2
Daniel Veillard4c004142003-10-07 11:33:24 +0000276
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000277/**
278 * xmlRelaxNGPartitions:
279 *
280 * A RelaxNGs partition associated to an interleave group
281 */
282typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
283typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
284struct _xmlRelaxNGPartition {
Daniel Veillard4c004142003-10-07 11:33:24 +0000285 int nbgroups; /* number of groups in the partitions */
286 xmlHashTablePtr triage; /* hash table used to direct nodes to the
287 * right group when possible */
288 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000289 xmlRelaxNGInterleaveGroupPtr *groups;
290};
291
292/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000293 * xmlRelaxNGValidState:
294 *
295 * A RelaxNGs validation state
296 */
297#define MAX_ATTR 20
298typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
299typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
300struct _xmlRelaxNGValidState {
Daniel Veillard4c004142003-10-07 11:33:24 +0000301 xmlNodePtr node; /* the current node */
302 xmlNodePtr seq; /* the sequence of children left to validate */
303 int nbAttrs; /* the number of attributes */
304 int maxAttrs; /* the size of attrs */
305 int nbAttrLeft; /* the number of attributes left to validate */
306 xmlChar *value; /* the value when operating on string */
307 xmlChar *endvalue; /* the end value when operating on string */
308 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000309};
310
311/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000312 * xmlRelaxNGStates:
313 *
314 * A RelaxNGs container for validation state
315 */
316typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
317typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
318struct _xmlRelaxNGStates {
Daniel Veillard4c004142003-10-07 11:33:24 +0000319 int nbState; /* the number of states */
320 int maxState; /* the size of the array */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000321 xmlRelaxNGValidStatePtr *tabState;
322};
323
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000324#define ERROR_IS_DUP 1
Daniel Veillard4c004142003-10-07 11:33:24 +0000325
Daniel Veillardfd573f12003-03-16 17:52:32 +0000326/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000327 * xmlRelaxNGValidError:
328 *
329 * A RelaxNGs validation error
330 */
331typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
332typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
333struct _xmlRelaxNGValidError {
Daniel Veillard4c004142003-10-07 11:33:24 +0000334 xmlRelaxNGValidErr err; /* the error number */
335 int flags; /* flags */
336 xmlNodePtr node; /* the current node */
337 xmlNodePtr seq; /* the current child */
338 const xmlChar *arg1; /* first arg */
339 const xmlChar *arg2; /* second arg */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000340};
341
342/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000343 * xmlRelaxNGValidCtxt:
344 *
345 * A RelaxNGs validation context
346 */
347
348struct _xmlRelaxNGValidCtxt {
Daniel Veillard4c004142003-10-07 11:33:24 +0000349 void *userData; /* user specific data block */
350 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
351 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000352 xmlStructuredErrorFunc serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000353 int nbErrors; /* number of errors in validation */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000354
Daniel Veillard4c004142003-10-07 11:33:24 +0000355 xmlRelaxNGPtr schema; /* The schema in use */
356 xmlDocPtr doc; /* the document being validated */
357 int flags; /* validation flags */
358 int depth; /* validation depth */
359 int idref; /* requires idref checking */
360 int errNo; /* the first error found */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000361
362 /*
363 * Errors accumulated in branches may have to be stacked to be
364 * provided back when it's sure they affect validation.
365 */
366 xmlRelaxNGValidErrorPtr err; /* Last error */
Daniel Veillard4c004142003-10-07 11:33:24 +0000367 int errNr; /* Depth of the error stack */
368 int errMax; /* Max depth of the error stack */
369 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000370
Daniel Veillard4c004142003-10-07 11:33:24 +0000371 xmlRelaxNGValidStatePtr state; /* the current validation state */
372 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000373
Daniel Veillard4c004142003-10-07 11:33:24 +0000374 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
375 int freeStatesNr;
376 int freeStatesMax;
377 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillardf4e55762003-04-15 23:32:22 +0000378
379 /*
380 * This is used for "progressive" validation
381 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000382 xmlRegExecCtxtPtr elem; /* the current element regexp */
383 int elemNr; /* the number of element validated */
384 int elemMax; /* the max depth of elements */
385 xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
386 int pstate; /* progressive state */
387 xmlNodePtr pnode; /* the current node */
388 xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */
389 int perr; /* signal error in content model
390 * outside the regexp */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000391};
392
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000393/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000394 * xmlRelaxNGInclude:
395 *
396 * Structure associated to a RelaxNGs document element
397 */
398struct _xmlRelaxNGInclude {
Daniel Veillard4c004142003-10-07 11:33:24 +0000399 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
400 xmlChar *href; /* the normalized href value */
401 xmlDocPtr doc; /* the associated XML document */
402 xmlRelaxNGDefinePtr content; /* the definitions */
403 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000404};
405
406/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000407 * xmlRelaxNGDocument:
408 *
409 * Structure associated to a RelaxNGs document element
410 */
411struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000412 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillard4c004142003-10-07 11:33:24 +0000413 xmlChar *href; /* the normalized href value */
414 xmlDocPtr doc; /* the associated XML document */
415 xmlRelaxNGDefinePtr content; /* the definitions */
416 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillard81c51e12009-08-14 18:52:10 +0200417 int externalRef; /* 1 if an external ref */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000418};
419
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000420
Daniel Veillard6eadf632003-01-23 18:29:16 +0000421/************************************************************************
Daniel Veillard4c004142003-10-07 11:33:24 +0000422 * *
423 * Some factorized error routines *
424 * *
425 ************************************************************************/
426
427/**
428 * xmlRngPErrMemory:
429 * @ctxt: an Relax-NG parser context
430 * @extra: extra informations
431 *
432 * Handle a redefinition of attribute error
433 */
434static void
435xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
436{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000437 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000438 xmlGenericErrorFunc channel = NULL;
439 void *data = NULL;
440
441 if (ctxt != NULL) {
Daniel Veillardb30ca312005-09-04 13:50:03 +0000442 if (ctxt->serror != NULL)
443 schannel = ctxt->serror;
444 else
445 channel = ctxt->error;
Daniel Veillard4c004142003-10-07 11:33:24 +0000446 data = ctxt->userData;
447 ctxt->nbErrors++;
448 }
449 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000450 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000451 NULL, NULL, XML_FROM_RELAXNGP,
452 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
453 NULL, NULL, 0, 0,
454 "Memory allocation failed : %s\n", extra);
455 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000456 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000457 NULL, NULL, XML_FROM_RELAXNGP,
458 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
459 NULL, NULL, 0, 0, "Memory allocation failed\n");
460}
461
462/**
463 * xmlRngVErrMemory:
464 * @ctxt: a Relax-NG validation context
465 * @extra: extra informations
466 *
467 * Handle a redefinition of attribute error
468 */
469static void
470xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
471{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000472 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000473 xmlGenericErrorFunc channel = NULL;
474 void *data = NULL;
475
476 if (ctxt != NULL) {
Daniel Veillardb30ca312005-09-04 13:50:03 +0000477 if (ctxt->serror != NULL)
478 schannel = ctxt->serror;
479 else
480 channel = ctxt->error;
Daniel Veillard4c004142003-10-07 11:33:24 +0000481 data = ctxt->userData;
482 ctxt->nbErrors++;
483 }
484 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000485 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000486 NULL, NULL, XML_FROM_RELAXNGV,
487 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
488 NULL, NULL, 0, 0,
489 "Memory allocation failed : %s\n", extra);
490 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000491 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000492 NULL, NULL, XML_FROM_RELAXNGV,
493 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
494 NULL, NULL, 0, 0, "Memory allocation failed\n");
495}
496
497/**
498 * xmlRngPErr:
499 * @ctxt: a Relax-NG parser context
500 * @node: the node raising the error
501 * @error: the error code
502 * @msg: message
503 * @str1: extra info
504 * @str2: extra info
505 *
506 * Handle a Relax NG Parsing error
507 */
508static void
509xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
510 const char *msg, const xmlChar * str1, const xmlChar * str2)
511{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000512 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000513 xmlGenericErrorFunc channel = NULL;
514 void *data = NULL;
515
516 if (ctxt != NULL) {
Daniel Veillardb30ca312005-09-04 13:50:03 +0000517 if (ctxt->serror != NULL)
518 schannel = ctxt->serror;
519 else
520 channel = ctxt->error;
Daniel Veillard4c004142003-10-07 11:33:24 +0000521 data = ctxt->userData;
522 ctxt->nbErrors++;
523 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000524 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000525 NULL, node, XML_FROM_RELAXNGP,
526 error, XML_ERR_ERROR, NULL, 0,
527 (const char *) str1, (const char *) str2, NULL, 0, 0,
528 msg, str1, str2);
529}
530
531/**
532 * xmlRngVErr:
533 * @ctxt: a Relax-NG validation context
534 * @node: the node raising the error
535 * @error: the error code
536 * @msg: message
537 * @str1: extra info
538 * @str2: extra info
539 *
540 * Handle a Relax NG Validation error
541 */
542static void
543xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
544 const char *msg, const xmlChar * str1, const xmlChar * str2)
545{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000546 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000547 xmlGenericErrorFunc channel = NULL;
548 void *data = NULL;
549
550 if (ctxt != NULL) {
Daniel Veillardb30ca312005-09-04 13:50:03 +0000551 if (ctxt->serror != NULL)
552 schannel = ctxt->serror;
553 else
554 channel = ctxt->error;
Daniel Veillard4c004142003-10-07 11:33:24 +0000555 data = ctxt->userData;
556 ctxt->nbErrors++;
557 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000558 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000559 NULL, node, XML_FROM_RELAXNGV,
560 error, XML_ERR_ERROR, NULL, 0,
561 (const char *) str1, (const char *) str2, NULL, 0, 0,
562 msg, str1, str2);
563}
564
565/************************************************************************
Daniel Veillard6eadf632003-01-23 18:29:16 +0000566 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000567 * Preliminary type checking interfaces *
568 * *
569 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +0000570
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000571/**
572 * xmlRelaxNGTypeHave:
573 * @data: data needed for the library
574 * @type: the type name
575 * @value: the value to check
576 *
577 * Function provided by a type library to check if a type is exported
578 *
579 * Returns 1 if yes, 0 if no and -1 in case of error.
580 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000581typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000582
583/**
584 * xmlRelaxNGTypeCheck:
585 * @data: data needed for the library
586 * @type: the type name
587 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000588 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000589 *
590 * Function provided by a type library to check if a value match a type
591 *
592 * Returns 1 if yes, 0 if no and -1 in case of error.
593 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000594typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
595 const xmlChar * value, void **result,
596 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000597
598/**
599 * xmlRelaxNGFacetCheck:
600 * @data: data needed for the library
601 * @type: the type name
602 * @facet: the facet name
603 * @val: the facet value
604 * @strval: the string value
605 * @value: the value to check
606 *
607 * Function provided by a type library to check a value facet
608 *
609 * Returns 1 if yes, 0 if no and -1 in case of error.
610 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000611typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
612 const xmlChar * facet,
613 const xmlChar * val,
614 const xmlChar * strval, void *value);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000615
616/**
617 * xmlRelaxNGTypeFree:
618 * @data: data needed for the library
619 * @result: the value to free
620 *
621 * Function provided by a type library to free a returned result
622 */
623typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000624
625/**
626 * xmlRelaxNGTypeCompare:
627 * @data: data needed for the library
628 * @type: the type name
629 * @value1: the first value
630 * @value2: the second value
631 *
632 * Function provided by a type library to compare two values accordingly
633 * to a type.
634 *
635 * Returns 1 if yes, 0 if no and -1 in case of error.
636 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000637typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
638 const xmlChar * value1,
639 xmlNodePtr ctxt1,
640 void *comp1,
641 const xmlChar * value2,
642 xmlNodePtr ctxt2);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000643typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
644typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
645struct _xmlRelaxNGTypeLibrary {
Daniel Veillard4c004142003-10-07 11:33:24 +0000646 const xmlChar *namespace; /* the datatypeLibrary value */
647 void *data; /* data needed for the library */
648 xmlRelaxNGTypeHave have; /* the export function */
649 xmlRelaxNGTypeCheck check; /* the checking function */
650 xmlRelaxNGTypeCompare comp; /* the compare function */
651 xmlRelaxNGFacetCheck facet; /* the facet check function */
652 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000653};
654
655/************************************************************************
656 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000657 * Allocation functions *
658 * *
659 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000660static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
661static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillard4c004142003-10-07 11:33:24 +0000662static void xmlRelaxNGNormExtSpace(xmlChar * value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000663static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillard4c004142003-10-07 11:33:24 +0000664static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
665 ATTRIBUTE_UNUSED,
666 xmlRelaxNGValidStatePtr state1,
667 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000668static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +0000669 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000670
671/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000672 * xmlRelaxNGFreeDocument:
673 * @docu: a document structure
674 *
675 * Deallocate a RelaxNG document structure.
676 */
677static void
678xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
679{
680 if (docu == NULL)
681 return;
682
683 if (docu->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000684 xmlFree(docu->href);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000685 if (docu->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000686 xmlFreeDoc(docu->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000687 if (docu->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000688 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000689 xmlFree(docu);
690}
691
692/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000693 * xmlRelaxNGFreeDocumentList:
694 * @docu: a list of document structure
695 *
696 * Deallocate a RelaxNG document structures.
697 */
698static void
699xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
700{
701 xmlRelaxNGDocumentPtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000702
Daniel Veillardc482e262003-02-26 14:48:48 +0000703 while (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000704 next = docu->next;
705 xmlRelaxNGFreeDocument(docu);
706 docu = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000707 }
708}
709
710/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000711 * xmlRelaxNGFreeInclude:
712 * @incl: a include structure
713 *
714 * Deallocate a RelaxNG include structure.
715 */
716static void
717xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
718{
719 if (incl == NULL)
720 return;
721
722 if (incl->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000723 xmlFree(incl->href);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000724 if (incl->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000725 xmlFreeDoc(incl->doc);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000726 if (incl->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000727 xmlRelaxNGFree(incl->schema);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000728 xmlFree(incl);
729}
730
731/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000732 * xmlRelaxNGFreeIncludeList:
733 * @incl: a include structure list
734 *
735 * Deallocate a RelaxNG include structure.
736 */
737static void
738xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
739{
740 xmlRelaxNGIncludePtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000741
Daniel Veillardc482e262003-02-26 14:48:48 +0000742 while (incl != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000743 next = incl->next;
744 xmlRelaxNGFreeInclude(incl);
745 incl = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000746 }
747}
748
749/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000750 * xmlRelaxNGNewRelaxNG:
751 * @ctxt: a Relax-NG validation context (optional)
752 *
753 * Allocate a new RelaxNG structure.
754 *
755 * Returns the newly allocated structure or NULL in case or error
756 */
757static xmlRelaxNGPtr
758xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
759{
760 xmlRelaxNGPtr ret;
761
762 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
763 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000764 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000765 return (NULL);
766 }
767 memset(ret, 0, sizeof(xmlRelaxNG));
768
769 return (ret);
770}
771
772/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000773 * xmlRelaxNGFreeInnerSchema:
774 * @schema: a schema structure
775 *
776 * Deallocate a RelaxNG schema structure.
777 */
778static void
779xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
780{
781 if (schema == NULL)
782 return;
783
784 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000785 xmlFreeDoc(schema->doc);
Daniel Veillardc482e262003-02-26 14:48:48 +0000786 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000787 int i;
Daniel Veillardc482e262003-02-26 14:48:48 +0000788
Daniel Veillard4c004142003-10-07 11:33:24 +0000789 for (i = 0; i < schema->defNr; i++)
790 xmlRelaxNGFreeDefine(schema->defTab[i]);
791 xmlFree(schema->defTab);
Daniel Veillardc482e262003-02-26 14:48:48 +0000792 }
793
794 xmlFree(schema);
795}
796
797/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000798 * xmlRelaxNGFree:
799 * @schema: a schema structure
800 *
801 * Deallocate a RelaxNG structure.
802 */
803void
804xmlRelaxNGFree(xmlRelaxNGPtr schema)
805{
806 if (schema == NULL)
807 return;
808
Daniel Veillard6eadf632003-01-23 18:29:16 +0000809 if (schema->topgrammar != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000810 xmlRelaxNGFreeGrammar(schema->topgrammar);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000811 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000812 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000813 if (schema->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000814 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000815 if (schema->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000816 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000817 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000818 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +0000819
Daniel Veillard4c004142003-10-07 11:33:24 +0000820 for (i = 0; i < schema->defNr; i++)
821 xmlRelaxNGFreeDefine(schema->defTab[i]);
822 xmlFree(schema->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +0000823 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000824
825 xmlFree(schema);
826}
827
828/**
829 * xmlRelaxNGNewGrammar:
830 * @ctxt: a Relax-NG validation context (optional)
831 *
832 * Allocate a new RelaxNG grammar.
833 *
834 * Returns the newly allocated structure or NULL in case or error
835 */
836static xmlRelaxNGGrammarPtr
837xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
838{
839 xmlRelaxNGGrammarPtr ret;
840
841 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
842 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000843 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000844 return (NULL);
845 }
846 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
847
848 return (ret);
849}
850
851/**
852 * xmlRelaxNGFreeGrammar:
853 * @grammar: a grammar structure
854 *
855 * Deallocate a RelaxNG grammar structure.
856 */
857static void
858xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
859{
860 if (grammar == NULL)
861 return;
862
Daniel Veillardc482e262003-02-26 14:48:48 +0000863 if (grammar->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000864 xmlRelaxNGFreeGrammar(grammar->children);
Daniel Veillardc482e262003-02-26 14:48:48 +0000865 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000866 if (grammar->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000867 xmlRelaxNGFreeGrammar(grammar->next);
Daniel Veillard419a7682003-02-03 23:22:49 +0000868 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000869 if (grammar->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000870 xmlHashFree(grammar->refs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000871 }
872 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000873 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000874 }
875
876 xmlFree(grammar);
877}
878
879/**
880 * xmlRelaxNGNewDefine:
881 * @ctxt: a Relax-NG validation context
882 * @node: the node in the input document.
883 *
884 * Allocate a new RelaxNG define.
885 *
886 * Returns the newly allocated structure or NULL in case or error
887 */
888static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000889xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000890{
891 xmlRelaxNGDefinePtr ret;
892
Daniel Veillard419a7682003-02-03 23:22:49 +0000893 if (ctxt->defMax == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000894 ctxt->defMax = 16;
895 ctxt->defNr = 0;
896 ctxt->defTab = (xmlRelaxNGDefinePtr *)
897 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
898 if (ctxt->defTab == NULL) {
899 xmlRngPErrMemory(ctxt, "allocating define\n");
900 return (NULL);
901 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000902 } else if (ctxt->defMax <= ctxt->defNr) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000903 xmlRelaxNGDefinePtr *tmp;
904
905 ctxt->defMax *= 2;
906 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
907 ctxt->defMax *
908 sizeof
909 (xmlRelaxNGDefinePtr));
910 if (tmp == NULL) {
911 xmlRngPErrMemory(ctxt, "allocating define\n");
912 return (NULL);
913 }
914 ctxt->defTab = tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +0000915 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000916 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
917 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000918 xmlRngPErrMemory(ctxt, "allocating define\n");
919 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000920 }
921 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000922 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000923 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000924 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000925 return (ret);
926}
927
928/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000929 * xmlRelaxNGFreePartition:
930 * @partitions: a partition set structure
931 *
932 * Deallocate RelaxNG partition set structures.
933 */
934static void
Daniel Veillard4c004142003-10-07 11:33:24 +0000935xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
936{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000937 xmlRelaxNGInterleaveGroupPtr group;
938 int j;
939
940 if (partitions != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000941 if (partitions->groups != NULL) {
942 for (j = 0; j < partitions->nbgroups; j++) {
943 group = partitions->groups[j];
944 if (group != NULL) {
945 if (group->defs != NULL)
946 xmlFree(group->defs);
947 if (group->attrs != NULL)
948 xmlFree(group->attrs);
949 xmlFree(group);
950 }
951 }
952 xmlFree(partitions->groups);
953 }
954 if (partitions->triage != NULL) {
955 xmlHashFree(partitions->triage, NULL);
956 }
957 xmlFree(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000958 }
959}
Daniel Veillard4c004142003-10-07 11:33:24 +0000960
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000961/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000962 * xmlRelaxNGFreeDefine:
963 * @define: a define structure
964 *
965 * Deallocate a RelaxNG define structure.
966 */
967static void
968xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
969{
970 if (define == NULL)
971 return;
972
Daniel Veillard4c004142003-10-07 11:33:24 +0000973 if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
974 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000975
Daniel Veillard4c004142003-10-07 11:33:24 +0000976 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
977 if ((lib != NULL) && (lib->freef != NULL))
978 lib->freef(lib->data, (void *) define->attrs);
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000979 }
Daniel Veillard4c004142003-10-07 11:33:24 +0000980 if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
981 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
982 if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
983 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000984 if (define->name != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000985 xmlFree(define->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000986 if (define->ns != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000987 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000988 if (define->value != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000989 xmlFree(define->value);
Daniel Veillard52b48c72003-04-13 19:53:42 +0000990 if (define->contModel != NULL)
991 xmlRegFreeRegexp(define->contModel);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000992 xmlFree(define);
993}
994
995/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000996 * xmlRelaxNGNewStates:
997 * @ctxt: a Relax-NG validation context
998 * @size: the default size for the container
999 *
1000 * Allocate a new RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +00001001 *
1002 * Returns the newly allocated structure or NULL in case or error
1003 */
1004static xmlRelaxNGStatesPtr
1005xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
1006{
1007 xmlRelaxNGStatesPtr ret;
1008
Daniel Veillard798024a2003-03-19 10:36:09 +00001009 if ((ctxt != NULL) &&
Daniel Veillard9fcd4622009-08-14 16:16:31 +02001010 (ctxt->freeStates != NULL) && (ctxt->freeStatesNr > 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001011 ctxt->freeStatesNr--;
1012 ret = ctxt->freeStates[ctxt->freeStatesNr];
1013 ret->nbState = 0;
1014 return (ret);
Daniel Veillard798024a2003-03-19 10:36:09 +00001015 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001016 if (size < 16)
1017 size = 16;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001018
1019 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
Daniel Veillard4c004142003-10-07 11:33:24 +00001020 (size -
1021 1) *
1022 sizeof(xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001023 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001024 xmlRngVErrMemory(ctxt, "allocating states\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001025 return (NULL);
1026 }
1027 ret->nbState = 0;
1028 ret->maxState = size;
Daniel Veillard4c004142003-10-07 11:33:24 +00001029 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
1030 sizeof
1031 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001032 if (ret->tabState == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001033 xmlRngVErrMemory(ctxt, "allocating states\n");
1034 xmlFree(ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001035 return (NULL);
1036 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001037 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001038}
1039
1040/**
Daniel Veillard798024a2003-03-19 10:36:09 +00001041 * xmlRelaxNGAddStateUniq:
1042 * @ctxt: a Relax-NG validation context
1043 * @states: the states container
1044 * @state: the validation state
1045 *
1046 * Add a RelaxNG validation state to the container without checking
1047 * for unicity.
1048 *
1049 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1050 */
1051static int
1052xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001053 xmlRelaxNGStatesPtr states,
1054 xmlRelaxNGValidStatePtr state)
Daniel Veillard798024a2003-03-19 10:36:09 +00001055{
1056 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001057 return (-1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001058 }
1059 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001060 xmlRelaxNGValidStatePtr *tmp;
1061 int size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001062
Daniel Veillard4c004142003-10-07 11:33:24 +00001063 size = states->maxState * 2;
1064 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1065 (size) *
1066 sizeof
1067 (xmlRelaxNGValidStatePtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001068 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001069 xmlRngVErrMemory(ctxt, "adding states\n");
1070 return (-1);
1071 }
1072 states->tabState = tmp;
1073 states->maxState = size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001074 }
1075 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001076 return (1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001077}
1078
1079/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001080 * xmlRelaxNGAddState:
1081 * @ctxt: a Relax-NG validation context
1082 * @states: the states container
1083 * @state: the validation state
1084 *
1085 * Add a RelaxNG validation state to the container
1086 *
1087 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1088 */
1089static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001090xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
1091 xmlRelaxNGStatesPtr states,
1092 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001093{
1094 int i;
1095
1096 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001097 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001098 }
1099 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001100 xmlRelaxNGValidStatePtr *tmp;
1101 int size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001102
Daniel Veillard4c004142003-10-07 11:33:24 +00001103 size = states->maxState * 2;
1104 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1105 (size) *
1106 sizeof
1107 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001108 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001109 xmlRngVErrMemory(ctxt, "adding states\n");
1110 return (-1);
1111 }
1112 states->tabState = tmp;
1113 states->maxState = size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001114 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001115 for (i = 0; i < states->nbState; i++) {
1116 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
1117 xmlRelaxNGFreeValidState(ctxt, state);
1118 return (0);
1119 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001120 }
1121 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001122 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001123}
1124
1125/**
1126 * xmlRelaxNGFreeStates:
1127 * @ctxt: a Relax-NG validation context
1128 * @states: teh container
1129 *
1130 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +00001131 */
1132static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001133xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001134 xmlRelaxNGStatesPtr states)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001135{
Daniel Veillard798024a2003-03-19 10:36:09 +00001136 if (states == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001137 return;
Daniel Veillard798024a2003-03-19 10:36:09 +00001138 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001139 ctxt->freeStatesMax = 40;
1140 ctxt->freeStatesNr = 0;
1141 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
1142 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
1143 if (ctxt->freeStates == NULL) {
1144 xmlRngVErrMemory(ctxt, "storing states\n");
1145 }
1146 } else if ((ctxt != NULL)
1147 && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
1148 xmlRelaxNGStatesPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001149
Daniel Veillard4c004142003-10-07 11:33:24 +00001150 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
1151 2 * ctxt->freeStatesMax *
1152 sizeof
1153 (xmlRelaxNGStatesPtr));
1154 if (tmp == NULL) {
1155 xmlRngVErrMemory(ctxt, "storing states\n");
1156 xmlFree(states->tabState);
1157 xmlFree(states);
1158 return;
1159 }
1160 ctxt->freeStates = tmp;
1161 ctxt->freeStatesMax *= 2;
Daniel Veillard798024a2003-03-19 10:36:09 +00001162 }
Daniel Veillard14b56432006-03-09 18:41:40 +00001163 if ((ctxt == NULL) || (ctxt->freeStates == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001164 xmlFree(states->tabState);
1165 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +00001166 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001167 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001168 }
1169}
1170
1171/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001172 * xmlRelaxNGNewValidState:
1173 * @ctxt: a Relax-NG validation context
1174 * @node: the current node or NULL for the document
1175 *
1176 * Allocate a new RelaxNG validation state
1177 *
1178 * Returns the newly allocated structure or NULL in case or error
1179 */
1180static xmlRelaxNGValidStatePtr
1181xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1182{
1183 xmlRelaxNGValidStatePtr ret;
1184 xmlAttrPtr attr;
1185 xmlAttrPtr attrs[MAX_ATTR];
1186 int nbAttrs = 0;
1187 xmlNodePtr root = NULL;
1188
1189 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001190 root = xmlDocGetRootElement(ctxt->doc);
1191 if (root == NULL)
1192 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001193 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001194 attr = node->properties;
1195 while (attr != NULL) {
1196 if (nbAttrs < MAX_ATTR)
1197 attrs[nbAttrs++] = attr;
1198 else
1199 nbAttrs++;
1200 attr = attr->next;
1201 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001202 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001203 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1204 ctxt->freeState->nbState--;
1205 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001206 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001207 ret =
1208 (xmlRelaxNGValidStatePtr)
1209 xmlMalloc(sizeof(xmlRelaxNGValidState));
1210 if (ret == NULL) {
1211 xmlRngVErrMemory(ctxt, "allocating states\n");
1212 return (NULL);
1213 }
1214 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001215 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001216 ret->value = NULL;
1217 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001218 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001219 ret->node = (xmlNodePtr) ctxt->doc;
1220 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001221 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001222 ret->node = node;
1223 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001224 }
1225 ret->nbAttrs = 0;
1226 if (nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001227 if (ret->attrs == NULL) {
1228 if (nbAttrs < 4)
1229 ret->maxAttrs = 4;
1230 else
1231 ret->maxAttrs = nbAttrs;
1232 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1233 sizeof(xmlAttrPtr));
1234 if (ret->attrs == NULL) {
1235 xmlRngVErrMemory(ctxt, "allocating states\n");
1236 return (ret);
1237 }
1238 } else if (ret->maxAttrs < nbAttrs) {
1239 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001240
Daniel Veillard4c004142003-10-07 11:33:24 +00001241 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1242 sizeof(xmlAttrPtr));
1243 if (tmp == NULL) {
1244 xmlRngVErrMemory(ctxt, "allocating states\n");
1245 return (ret);
1246 }
1247 ret->attrs = tmp;
1248 ret->maxAttrs = nbAttrs;
1249 }
1250 ret->nbAttrs = nbAttrs;
1251 if (nbAttrs < MAX_ATTR) {
1252 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1253 } else {
1254 attr = node->properties;
1255 nbAttrs = 0;
1256 while (attr != NULL) {
1257 ret->attrs[nbAttrs++] = attr;
1258 attr = attr->next;
1259 }
1260 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001261 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001262 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001263 return (ret);
1264}
1265
1266/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001267 * xmlRelaxNGCopyValidState:
1268 * @ctxt: a Relax-NG validation context
1269 * @state: a validation state
1270 *
1271 * Copy the validation state
1272 *
1273 * Returns the newly allocated structure or NULL in case or error
1274 */
1275static xmlRelaxNGValidStatePtr
1276xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001277 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001278{
1279 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001280 unsigned int maxAttrs;
1281 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001282
1283 if (state == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001284 return (NULL);
1285 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1286 ctxt->freeState->nbState--;
1287 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001288 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001289 ret =
1290 (xmlRelaxNGValidStatePtr)
1291 xmlMalloc(sizeof(xmlRelaxNGValidState));
1292 if (ret == NULL) {
1293 xmlRngVErrMemory(ctxt, "allocating states\n");
1294 return (NULL);
1295 }
1296 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001297 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001298 attrs = ret->attrs;
1299 maxAttrs = ret->maxAttrs;
1300 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1301 ret->attrs = attrs;
1302 ret->maxAttrs = maxAttrs;
1303 if (state->nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001304 if (ret->attrs == NULL) {
1305 ret->maxAttrs = state->maxAttrs;
1306 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1307 sizeof(xmlAttrPtr));
1308 if (ret->attrs == NULL) {
1309 xmlRngVErrMemory(ctxt, "allocating states\n");
1310 ret->nbAttrs = 0;
1311 return (ret);
1312 }
1313 } else if (ret->maxAttrs < state->nbAttrs) {
1314 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001315
Daniel Veillard4c004142003-10-07 11:33:24 +00001316 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1317 sizeof(xmlAttrPtr));
1318 if (tmp == NULL) {
1319 xmlRngVErrMemory(ctxt, "allocating states\n");
1320 ret->nbAttrs = 0;
1321 return (ret);
1322 }
1323 ret->maxAttrs = state->maxAttrs;
1324 ret->attrs = tmp;
1325 }
1326 memcpy(ret->attrs, state->attrs,
1327 state->nbAttrs * sizeof(xmlAttrPtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001328 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001329 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001330}
1331
1332/**
1333 * xmlRelaxNGEqualValidState:
1334 * @ctxt: a Relax-NG validation context
1335 * @state1: a validation state
1336 * @state2: a validation state
1337 *
1338 * Compare the validation states for equality
1339 *
1340 * Returns 1 if equald, 0 otherwise
1341 */
1342static int
1343xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00001344 xmlRelaxNGValidStatePtr state1,
1345 xmlRelaxNGValidStatePtr state2)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001346{
1347 int i;
1348
1349 if ((state1 == NULL) || (state2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00001350 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001351 if (state1 == state2)
Daniel Veillard4c004142003-10-07 11:33:24 +00001352 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001353 if (state1->node != state2->node)
Daniel Veillard4c004142003-10-07 11:33:24 +00001354 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001355 if (state1->seq != state2->seq)
Daniel Veillard4c004142003-10-07 11:33:24 +00001356 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001357 if (state1->nbAttrLeft != state2->nbAttrLeft)
Daniel Veillard4c004142003-10-07 11:33:24 +00001358 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001359 if (state1->nbAttrs != state2->nbAttrs)
Daniel Veillard4c004142003-10-07 11:33:24 +00001360 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001361 if (state1->endvalue != state2->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00001362 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001363 if ((state1->value != state2->value) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001364 (!xmlStrEqual(state1->value, state2->value)))
1365 return (0);
1366 for (i = 0; i < state1->nbAttrs; i++) {
1367 if (state1->attrs[i] != state2->attrs[i])
1368 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001369 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001370 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001371}
1372
1373/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001374 * xmlRelaxNGFreeValidState:
1375 * @state: a validation state structure
1376 *
1377 * Deallocate a RelaxNG validation state structure.
1378 */
1379static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001380xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001381 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001382{
1383 if (state == NULL)
1384 return;
1385
Daniel Veillard798024a2003-03-19 10:36:09 +00001386 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001387 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
Daniel Veillard798024a2003-03-19 10:36:09 +00001388 }
1389 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001390 if (state->attrs != NULL)
1391 xmlFree(state->attrs);
1392 xmlFree(state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001393 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001394 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001395 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001396}
1397
1398/************************************************************************
1399 * *
Daniel Veillard03c2f0a2004-01-25 19:54:59 +00001400 * Semi internal functions *
1401 * *
1402 ************************************************************************/
1403
1404/**
1405 * xmlRelaxParserSetFlag:
1406 * @ctxt: a RelaxNG parser context
1407 * @flags: a set of flags values
1408 *
1409 * Semi private function used to pass informations to a parser context
1410 * which are a combination of xmlRelaxNGParserFlag .
1411 *
1412 * Returns 0 if success and -1 in case of error
1413 */
1414int
1415xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
1416{
1417 if (ctxt == NULL) return(-1);
1418 if (flags & XML_RELAXNGP_FREE_DOC) {
1419 ctxt->crng |= XML_RELAXNGP_FREE_DOC;
1420 flags -= XML_RELAXNGP_FREE_DOC;
1421 }
1422 if (flags & XML_RELAXNGP_CRNG) {
1423 ctxt->crng |= XML_RELAXNGP_CRNG;
1424 flags -= XML_RELAXNGP_CRNG;
1425 }
1426 if (flags != 0) return(-1);
1427 return(0);
1428}
1429
1430/************************************************************************
1431 * *
1432 * Document functions *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001433 * *
1434 ************************************************************************/
1435static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001436 xmlDocPtr doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001437
1438/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001439 * xmlRelaxNGIncludePush:
1440 * @ctxt: the parser context
1441 * @value: the element doc
1442 *
1443 * Pushes a new include on top of the include stack
1444 *
1445 * Returns 0 in case of error, the index in the stack otherwise
1446 */
1447static int
1448xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001449 xmlRelaxNGIncludePtr value)
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001450{
1451 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001452 ctxt->incMax = 4;
1453 ctxt->incNr = 0;
1454 ctxt->incTab =
1455 (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
1456 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001457 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001458 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001459 return (0);
1460 }
1461 }
1462 if (ctxt->incNr >= ctxt->incMax) {
1463 ctxt->incMax *= 2;
1464 ctxt->incTab =
1465 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001466 ctxt->incMax *
1467 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001468 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001469 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001470 return (0);
1471 }
1472 }
1473 ctxt->incTab[ctxt->incNr] = value;
1474 ctxt->inc = value;
1475 return (ctxt->incNr++);
1476}
1477
1478/**
1479 * xmlRelaxNGIncludePop:
1480 * @ctxt: the parser context
1481 *
1482 * Pops the top include from the include stack
1483 *
1484 * Returns the include just removed
1485 */
1486static xmlRelaxNGIncludePtr
1487xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1488{
1489 xmlRelaxNGIncludePtr ret;
1490
1491 if (ctxt->incNr <= 0)
Daniel Veillard24505b02005-07-28 23:49:35 +00001492 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001493 ctxt->incNr--;
1494 if (ctxt->incNr > 0)
1495 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1496 else
1497 ctxt->inc = NULL;
1498 ret = ctxt->incTab[ctxt->incNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00001499 ctxt->incTab[ctxt->incNr] = NULL;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001500 return (ret);
1501}
1502
1503/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001504 * xmlRelaxNGRemoveRedefine:
1505 * @ctxt: the parser context
1506 * @URL: the normalized URL
1507 * @target: the included target
1508 * @name: the define name to eliminate
1509 *
1510 * Applies the elimination algorithm of 4.7
1511 *
1512 * Returns 0 in case of error, 1 in case of success.
1513 */
1514static int
1515xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001516 const xmlChar * URL ATTRIBUTE_UNUSED,
1517 xmlNodePtr target, const xmlChar * name)
1518{
Daniel Veillard5add8682003-03-10 13:13:58 +00001519 int found = 0;
1520 xmlNodePtr tmp, tmp2;
1521 xmlChar *name2;
1522
1523#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001524 if (name == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001525 xmlGenericError(xmlGenericErrorContext,
1526 "Elimination of <include> start from %s\n", URL);
Daniel Veillard952379b2003-03-17 15:37:12 +00001527 else
Daniel Veillard4c004142003-10-07 11:33:24 +00001528 xmlGenericError(xmlGenericErrorContext,
1529 "Elimination of <include> define %s from %s\n",
1530 name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001531#endif
1532 tmp = target;
1533 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001534 tmp2 = tmp->next;
1535 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1536 found = 1;
1537 xmlUnlinkNode(tmp);
1538 xmlFreeNode(tmp);
1539 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1540 name2 = xmlGetProp(tmp, BAD_CAST "name");
1541 xmlRelaxNGNormExtSpace(name2);
1542 if (name2 != NULL) {
1543 if (xmlStrEqual(name, name2)) {
1544 found = 1;
1545 xmlUnlinkNode(tmp);
1546 xmlFreeNode(tmp);
1547 }
1548 xmlFree(name2);
1549 }
1550 } else if (IS_RELAXNG(tmp, "include")) {
1551 xmlChar *href = NULL;
Daniel Veillard807daf82004-02-22 22:13:27 +00001552 xmlRelaxNGDocumentPtr inc = tmp->psvi;
Daniel Veillard5add8682003-03-10 13:13:58 +00001553
Daniel Veillard4c004142003-10-07 11:33:24 +00001554 if ((inc != NULL) && (inc->doc != NULL) &&
1555 (inc->doc->children != NULL)) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001556
Daniel Veillard4c004142003-10-07 11:33:24 +00001557 if (xmlStrEqual
1558 (inc->doc->children->name, BAD_CAST "grammar")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001559#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001560 href = xmlGetProp(tmp, BAD_CAST "href");
Daniel Veillard5add8682003-03-10 13:13:58 +00001561#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00001562 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1563 inc->doc->children->
1564 children, name) == 1) {
1565 found = 1;
1566 }
Daniel Veillard14b56432006-03-09 18:41:40 +00001567#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001568 if (href != NULL)
1569 xmlFree(href);
Daniel Veillard14b56432006-03-09 18:41:40 +00001570#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00001571 }
1572 }
1573 }
1574 tmp = tmp2;
Daniel Veillard5add8682003-03-10 13:13:58 +00001575 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001576 return (found);
Daniel Veillard5add8682003-03-10 13:13:58 +00001577}
1578
1579/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001580 * xmlRelaxNGLoadInclude:
1581 * @ctxt: the parser context
1582 * @URL: the normalized URL
1583 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001584 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001585 *
1586 * First lookup if the document is already loaded into the parser context,
1587 * check against recursion. If not found the resource is loaded and
1588 * the content is preprocessed before being returned back to the caller.
1589 *
1590 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1591 */
1592static xmlRelaxNGIncludePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001593xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
1594 xmlNodePtr node, const xmlChar * ns)
1595{
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001596 xmlRelaxNGIncludePtr ret = NULL;
1597 xmlDocPtr doc;
1598 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001599 xmlNodePtr root, cur;
1600
1601#ifdef DEBUG_INCLUDE
1602 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001603 "xmlRelaxNGLoadInclude(%s)\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001604#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001605
1606 /*
1607 * check against recursion in the stack
1608 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001609 for (i = 0; i < ctxt->incNr; i++) {
1610 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1611 xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
1612 "Detected an Include recursion for %s\n", URL,
1613 NULL);
1614 return (NULL);
1615 }
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001616 }
1617
1618 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001619 * load the document
1620 */
Daniel Veillard87247e82004-01-13 20:42:02 +00001621 doc = xmlReadFile((const char *) URL,NULL,0);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001622 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001623 xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
1624 "xmlRelaxNG: could not load %s\n", URL, NULL);
1625 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001626 }
Daniel Veillard5add8682003-03-10 13:13:58 +00001627#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001628 xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001629#endif
1630
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001631 /*
1632 * Allocate the document structures and register it first.
1633 */
1634 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1635 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001636 xmlRngPErrMemory(ctxt, "allocating include\n");
1637 xmlFreeDoc(doc);
1638 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001639 }
1640 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1641 ret->doc = doc;
1642 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001643 ret->next = ctxt->includes;
1644 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001645
1646 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001647 * transmit the ns if needed
1648 */
1649 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001650 root = xmlDocGetRootElement(doc);
1651 if (root != NULL) {
1652 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1653 xmlSetProp(root, BAD_CAST "ns", ns);
1654 }
1655 }
Daniel Veillard416589a2003-02-17 17:25:42 +00001656 }
1657
1658 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001659 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001660 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001661 xmlRelaxNGIncludePush(ctxt, ret);
1662
1663 /*
1664 * Some preprocessing of the document content, this include recursing
1665 * in the include stack.
1666 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001667#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001668 xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001669#endif
1670
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001671 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1672 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001673 ctxt->inc = NULL;
1674 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001675 }
1676
1677 /*
1678 * Pop up the include from the stack
1679 */
1680 xmlRelaxNGIncludePop(ctxt);
1681
Daniel Veillard5add8682003-03-10 13:13:58 +00001682#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001683 xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001684#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001685 /*
1686 * Check that the top element is a grammar
1687 */
1688 root = xmlDocGetRootElement(doc);
1689 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001690 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
1691 "xmlRelaxNG: included document is empty %s\n", URL,
1692 NULL);
1693 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001694 }
1695 if (!IS_RELAXNG(root, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001696 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
1697 "xmlRelaxNG: included document %s root is not a grammar\n",
1698 URL, NULL);
1699 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001700 }
1701
1702 /*
1703 * Elimination of redefined rules in the include.
1704 */
1705 cur = node->children;
1706 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001707 if (IS_RELAXNG(cur, "start")) {
1708 int found = 0;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001709
Daniel Veillard4c004142003-10-07 11:33:24 +00001710 found =
1711 xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
1712 if (!found) {
1713 xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
1714 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1715 URL, NULL);
1716 }
1717 } else if (IS_RELAXNG(cur, "define")) {
1718 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001719
Daniel Veillard4c004142003-10-07 11:33:24 +00001720 name = xmlGetProp(cur, BAD_CAST "name");
1721 if (name == NULL) {
1722 xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
1723 "xmlRelaxNG: include %s has define without name\n",
1724 URL, NULL);
1725 } else {
1726 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001727
Daniel Veillard4c004142003-10-07 11:33:24 +00001728 xmlRelaxNGNormExtSpace(name);
1729 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1730 root->children, name);
1731 if (!found) {
1732 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
1733 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1734 URL, name);
1735 }
1736 xmlFree(name);
1737 }
1738 }
1739 cur = cur->next;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001740 }
1741
1742
Daniel Veillard4c004142003-10-07 11:33:24 +00001743 return (ret);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001744}
1745
1746/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001747 * xmlRelaxNGValidErrorPush:
1748 * @ctxt: the validation context
1749 * @err: the error code
1750 * @arg1: the first string argument
1751 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001752 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001753 *
1754 * Pushes a new error on top of the error stack
1755 *
1756 * Returns 0 in case of error, the index in the stack otherwise
1757 */
1758static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001759xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
1760 xmlRelaxNGValidErr err, const xmlChar * arg1,
1761 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001762{
1763 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00001764
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001765#ifdef DEBUG_ERROR
1766 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001767 "Pushing error %d at %d on stack\n", err, ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001768#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00001769 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001770 ctxt->errMax = 8;
1771 ctxt->errNr = 0;
1772 ctxt->errTab =
1773 (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
1774 sizeof
1775 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001776 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001777 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001778 return (0);
1779 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001780 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001781 }
1782 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001783 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001784 ctxt->errTab =
1785 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001786 ctxt->errMax *
1787 sizeof
1788 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001789 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001790 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001791 return (0);
1792 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001793 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001794 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001795 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001796 (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
1797 return (ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001798 cur = &ctxt->errTab[ctxt->errNr];
1799 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001800 if (dup) {
1801 cur->arg1 = xmlStrdup(arg1);
1802 cur->arg2 = xmlStrdup(arg2);
Daniel Veillard4c004142003-10-07 11:33:24 +00001803 cur->flags = ERROR_IS_DUP;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001804 } else {
1805 cur->arg1 = arg1;
1806 cur->arg2 = arg2;
Daniel Veillard4c004142003-10-07 11:33:24 +00001807 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001808 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001809 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001810 cur->node = ctxt->state->node;
1811 cur->seq = ctxt->state->seq;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001812 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001813 cur->node = NULL;
1814 cur->seq = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001815 }
1816 ctxt->err = cur;
1817 return (ctxt->errNr++);
1818}
1819
1820/**
1821 * xmlRelaxNGValidErrorPop:
1822 * @ctxt: the validation context
1823 *
1824 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001825 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001826static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001827xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1828{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001829 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001830
Daniel Veillard580ced82003-03-21 21:22:48 +00001831 if (ctxt->errNr <= 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001832 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001833 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001834 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001835 ctxt->errNr--;
1836 if (ctxt->errNr > 0)
1837 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1838 else
1839 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001840 cur = &ctxt->errTab[ctxt->errNr];
1841 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001842 if (cur->arg1 != NULL)
1843 xmlFree((xmlChar *) cur->arg1);
1844 cur->arg1 = NULL;
1845 if (cur->arg2 != NULL)
1846 xmlFree((xmlChar *) cur->arg2);
1847 cur->arg2 = NULL;
1848 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001849 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001850}
1851
Daniel Veillard42f12e92003-03-07 18:32:59 +00001852/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001853 * xmlRelaxNGDocumentPush:
1854 * @ctxt: the parser context
1855 * @value: the element doc
1856 *
1857 * Pushes a new doc on top of the doc stack
1858 *
1859 * Returns 0 in case of error, the index in the stack otherwise
1860 */
1861static int
1862xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001863 xmlRelaxNGDocumentPtr value)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001864{
1865 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001866 ctxt->docMax = 4;
1867 ctxt->docNr = 0;
1868 ctxt->docTab =
1869 (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
1870 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001871 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001872 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001873 return (0);
1874 }
1875 }
1876 if (ctxt->docNr >= ctxt->docMax) {
1877 ctxt->docMax *= 2;
1878 ctxt->docTab =
1879 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001880 ctxt->docMax *
1881 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001882 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001883 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001884 return (0);
1885 }
1886 }
1887 ctxt->docTab[ctxt->docNr] = value;
1888 ctxt->doc = value;
1889 return (ctxt->docNr++);
1890}
1891
1892/**
1893 * xmlRelaxNGDocumentPop:
1894 * @ctxt: the parser context
1895 *
1896 * Pops the top doc from the doc stack
1897 *
1898 * Returns the doc just removed
1899 */
1900static xmlRelaxNGDocumentPtr
1901xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1902{
1903 xmlRelaxNGDocumentPtr ret;
1904
1905 if (ctxt->docNr <= 0)
Daniel Veillard24505b02005-07-28 23:49:35 +00001906 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001907 ctxt->docNr--;
1908 if (ctxt->docNr > 0)
1909 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1910 else
1911 ctxt->doc = NULL;
1912 ret = ctxt->docTab[ctxt->docNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00001913 ctxt->docTab[ctxt->docNr] = NULL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001914 return (ret);
1915}
1916
1917/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001918 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001919 * @ctxt: the parser context
1920 * @URL: the normalized URL
1921 * @ns: the inherited ns if any
1922 *
1923 * First lookup if the document is already loaded into the parser context,
1924 * check against recursion. If not found the resource is loaded and
1925 * the content is preprocessed before being returned back to the caller.
1926 *
1927 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1928 */
1929static xmlRelaxNGDocumentPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001930xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
1931 const xmlChar * URL, const xmlChar * ns)
1932{
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001933 xmlRelaxNGDocumentPtr ret = NULL;
1934 xmlDocPtr doc;
1935 xmlNodePtr root;
1936 int i;
1937
1938 /*
1939 * check against recursion in the stack
1940 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001941 for (i = 0; i < ctxt->docNr; i++) {
1942 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1943 xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
1944 "Detected an externalRef recursion for %s\n", URL,
1945 NULL);
1946 return (NULL);
1947 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001948 }
1949
1950 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001951 * load the document
1952 */
Daniel Veillard87247e82004-01-13 20:42:02 +00001953 doc = xmlReadFile((const char *) URL,NULL,0);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001954 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001955 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
1956 "xmlRelaxNG: could not load %s\n", URL, NULL);
1957 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001958 }
1959
1960 /*
1961 * Allocate the document structures and register it first.
1962 */
1963 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1964 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001965 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
1966 "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
1967 xmlFreeDoc(doc);
1968 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001969 }
1970 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1971 ret->doc = doc;
1972 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001973 ret->next = ctxt->documents;
Daniel Veillard81c51e12009-08-14 18:52:10 +02001974 ret->externalRef = 1;
Daniel Veillardc482e262003-02-26 14:48:48 +00001975 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001976
1977 /*
1978 * transmit the ns if needed
1979 */
1980 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001981 root = xmlDocGetRootElement(doc);
1982 if (root != NULL) {
1983 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1984 xmlSetProp(root, BAD_CAST "ns", ns);
1985 }
1986 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001987 }
1988
1989 /*
1990 * push it on the stack and register it in the hash table
1991 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001992 xmlRelaxNGDocumentPush(ctxt, ret);
1993
1994 /*
1995 * Some preprocessing of the document content
1996 */
1997 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1998 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001999 ctxt->doc = NULL;
2000 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002001 }
2002
2003 xmlRelaxNGDocumentPop(ctxt);
2004
Daniel Veillard4c004142003-10-07 11:33:24 +00002005 return (ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002006}
2007
2008/************************************************************************
2009 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00002010 * Error functions *
2011 * *
2012 ************************************************************************/
2013
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002014#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
2015#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2016#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2017#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2018#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002019
Daniel Veillard231d7912003-02-09 14:22:17 +00002020static const char *
Daniel Veillard4c004142003-10-07 11:33:24 +00002021xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
2022{
Daniel Veillard231d7912003-02-09 14:22:17 +00002023 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002024 return ("none");
2025 switch (def->type) {
2026 case XML_RELAXNG_EMPTY:
2027 return ("empty");
2028 case XML_RELAXNG_NOT_ALLOWED:
2029 return ("notAllowed");
2030 case XML_RELAXNG_EXCEPT:
2031 return ("except");
2032 case XML_RELAXNG_TEXT:
2033 return ("text");
2034 case XML_RELAXNG_ELEMENT:
2035 return ("element");
2036 case XML_RELAXNG_DATATYPE:
2037 return ("datatype");
2038 case XML_RELAXNG_VALUE:
2039 return ("value");
2040 case XML_RELAXNG_LIST:
2041 return ("list");
2042 case XML_RELAXNG_ATTRIBUTE:
2043 return ("attribute");
2044 case XML_RELAXNG_DEF:
2045 return ("def");
2046 case XML_RELAXNG_REF:
2047 return ("ref");
2048 case XML_RELAXNG_EXTERNALREF:
2049 return ("externalRef");
2050 case XML_RELAXNG_PARENTREF:
2051 return ("parentRef");
2052 case XML_RELAXNG_OPTIONAL:
2053 return ("optional");
2054 case XML_RELAXNG_ZEROORMORE:
2055 return ("zeroOrMore");
2056 case XML_RELAXNG_ONEORMORE:
2057 return ("oneOrMore");
2058 case XML_RELAXNG_CHOICE:
2059 return ("choice");
2060 case XML_RELAXNG_GROUP:
2061 return ("group");
2062 case XML_RELAXNG_INTERLEAVE:
2063 return ("interleave");
2064 case XML_RELAXNG_START:
2065 return ("start");
2066 case XML_RELAXNG_NOOP:
2067 return ("noop");
2068 case XML_RELAXNG_PARAM:
2069 return ("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00002070 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002071 return ("unknown");
Daniel Veillard231d7912003-02-09 14:22:17 +00002072}
Daniel Veillardd2298792003-02-14 16:54:11 +00002073
Daniel Veillard6eadf632003-01-23 18:29:16 +00002074/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002075 * xmlRelaxNGGetErrorString:
2076 * @err: the error code
2077 * @arg1: the first string argument
2078 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00002079 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00002080 * computes a formatted error string for the given error code and args
2081 *
2082 * Returns the error string, it must be deallocated by the caller
2083 */
2084static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00002085xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
2086 const xmlChar * arg2)
2087{
Daniel Veillard42f12e92003-03-07 18:32:59 +00002088 char msg[1000];
2089
2090 if (arg1 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002091 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002092 if (arg2 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002093 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002094
2095 msg[0] = 0;
2096 switch (err) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002097 case XML_RELAXNG_OK:
2098 return (NULL);
2099 case XML_RELAXNG_ERR_MEMORY:
2100 return (xmlCharStrdup("out of memory\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002101 case XML_RELAXNG_ERR_TYPE:
Daniel Veillard4c004142003-10-07 11:33:24 +00002102 snprintf(msg, 1000, "failed to validate type %s\n", arg1);
2103 break;
2104 case XML_RELAXNG_ERR_TYPEVAL:
2105 snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
2106 arg2);
2107 break;
2108 case XML_RELAXNG_ERR_DUPID:
2109 snprintf(msg, 1000, "ID %s redefined\n", arg1);
2110 break;
2111 case XML_RELAXNG_ERR_TYPECMP:
2112 snprintf(msg, 1000, "failed to compare type %s\n", arg1);
2113 break;
2114 case XML_RELAXNG_ERR_NOSTATE:
2115 return (xmlCharStrdup("Internal error: no state\n"));
2116 case XML_RELAXNG_ERR_NODEFINE:
2117 return (xmlCharStrdup("Internal error: no define\n"));
2118 case XML_RELAXNG_ERR_INTERNAL:
2119 snprintf(msg, 1000, "Internal error: %s\n", arg1);
2120 break;
2121 case XML_RELAXNG_ERR_LISTEXTRA:
2122 snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
2123 break;
2124 case XML_RELAXNG_ERR_INTERNODATA:
2125 return (xmlCharStrdup
2126 ("Internal: interleave block has no data\n"));
2127 case XML_RELAXNG_ERR_INTERSEQ:
2128 return (xmlCharStrdup("Invalid sequence in interleave\n"));
2129 case XML_RELAXNG_ERR_INTEREXTRA:
2130 snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
2131 break;
2132 case XML_RELAXNG_ERR_ELEMNAME:
2133 snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
2134 arg2);
2135 break;
2136 case XML_RELAXNG_ERR_ELEMNONS:
2137 snprintf(msg, 1000, "Expecting a namespace for element %s\n",
2138 arg1);
2139 break;
2140 case XML_RELAXNG_ERR_ELEMWRONGNS:
2141 snprintf(msg, 1000,
2142 "Element %s has wrong namespace: expecting %s\n", arg1,
2143 arg2);
2144 break;
2145 case XML_RELAXNG_ERR_ELEMWRONG:
2146 snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
2147 break;
2148 case XML_RELAXNG_ERR_TEXTWRONG:
2149 snprintf(msg, 1000,
2150 "Did not expect text in element %s content\n", arg1);
2151 break;
2152 case XML_RELAXNG_ERR_ELEMEXTRANS:
2153 snprintf(msg, 1000, "Expecting no namespace for element %s\n",
2154 arg1);
2155 break;
2156 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
2157 snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
2158 break;
2159 case XML_RELAXNG_ERR_NOELEM:
2160 snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
2161 arg1);
2162 break;
2163 case XML_RELAXNG_ERR_NOTELEM:
2164 return (xmlCharStrdup("Expecting an element got text\n"));
2165 case XML_RELAXNG_ERR_ATTRVALID:
2166 snprintf(msg, 1000, "Element %s failed to validate attributes\n",
2167 arg1);
2168 break;
2169 case XML_RELAXNG_ERR_CONTENTVALID:
2170 snprintf(msg, 1000, "Element %s failed to validate content\n",
2171 arg1);
2172 break;
2173 case XML_RELAXNG_ERR_EXTRACONTENT:
2174 snprintf(msg, 1000, "Element %s has extra content: %s\n",
2175 arg1, arg2);
2176 break;
2177 case XML_RELAXNG_ERR_INVALIDATTR:
2178 snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
2179 arg1, arg2);
2180 break;
2181 case XML_RELAXNG_ERR_LACKDATA:
2182 snprintf(msg, 1000, "Datatype element %s contains no data\n",
2183 arg1);
2184 break;
2185 case XML_RELAXNG_ERR_DATAELEM:
2186 snprintf(msg, 1000, "Datatype element %s has child elements\n",
2187 arg1);
2188 break;
2189 case XML_RELAXNG_ERR_VALELEM:
2190 snprintf(msg, 1000, "Value element %s has child elements\n",
2191 arg1);
2192 break;
2193 case XML_RELAXNG_ERR_LISTELEM:
2194 snprintf(msg, 1000, "List element %s has child elements\n",
2195 arg1);
2196 break;
2197 case XML_RELAXNG_ERR_DATATYPE:
2198 snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
2199 break;
2200 case XML_RELAXNG_ERR_VALUE:
2201 snprintf(msg, 1000, "Error validating value %s\n", arg1);
2202 break;
2203 case XML_RELAXNG_ERR_LIST:
2204 return (xmlCharStrdup("Error validating list\n"));
2205 case XML_RELAXNG_ERR_NOGRAMMAR:
2206 return (xmlCharStrdup("No top grammar defined\n"));
2207 case XML_RELAXNG_ERR_EXTRADATA:
2208 return (xmlCharStrdup("Extra data in the document\n"));
2209 default:
2210 return (xmlCharStrdup("Unknown error !\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002211 }
2212 if (msg[0] == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002213 snprintf(msg, 1000, "Unknown error code %d\n", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002214 }
Daniel Veillardadbb0e62003-05-10 20:02:45 +00002215 msg[1000 - 1] = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00002216 return (xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002217}
2218
2219/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002220 * xmlRelaxNGShowValidError:
2221 * @ctxt: the validation context
2222 * @err: the error number
2223 * @node: the node
2224 * @child: the node child generating the problem.
2225 * @arg1: the first argument
2226 * @arg2: the second argument
2227 *
2228 * Show a validation error.
2229 */
2230static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002231xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
2232 xmlRelaxNGValidErr err, xmlNodePtr node,
2233 xmlNodePtr child, const xmlChar * arg1,
2234 const xmlChar * arg2)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002235{
2236 xmlChar *msg;
2237
Daniel Veillardb30ca312005-09-04 13:50:03 +00002238 if (ctxt->flags & FLAGS_NOERROR)
Daniel Veillardf03a8cd2005-09-04 12:01:57 +00002239 return;
2240
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002241#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002242 xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002243#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002244 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2245 if (msg == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002246 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002247
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002248 if (ctxt->errNo == XML_RELAXNG_OK)
Daniel Veillard4c004142003-10-07 11:33:24 +00002249 ctxt->errNo = err;
2250 xmlRngVErr(ctxt, (child == NULL ? node : child), err,
2251 (const char *) msg, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002252 xmlFree(msg);
2253}
2254
2255/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002256 * xmlRelaxNGPopErrors:
2257 * @ctxt: the validation context
2258 * @level: the error level in the stack
2259 *
2260 * pop and discard all errors until the given level is reached
2261 */
2262static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002263xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
2264{
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002265 int i;
2266 xmlRelaxNGValidErrorPtr err;
2267
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002268#ifdef DEBUG_ERROR
2269 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002270 "Pop errors till level %d\n", level);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002271#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002272 for (i = level; i < ctxt->errNr; i++) {
2273 err = &ctxt->errTab[i];
2274 if (err->flags & ERROR_IS_DUP) {
2275 if (err->arg1 != NULL)
2276 xmlFree((xmlChar *) err->arg1);
2277 err->arg1 = NULL;
2278 if (err->arg2 != NULL)
2279 xmlFree((xmlChar *) err->arg2);
2280 err->arg2 = NULL;
2281 err->flags = 0;
2282 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002283 }
2284 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002285 if (ctxt->errNr <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002286 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002287}
Daniel Veillard4c004142003-10-07 11:33:24 +00002288
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002289/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002290 * xmlRelaxNGDumpValidError:
2291 * @ctxt: the validation context
2292 *
2293 * Show all validation error over a given index.
2294 */
2295static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002296xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
2297{
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002298 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002299 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002300
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002301#ifdef DEBUG_ERROR
2302 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002303 "Dumping error stack %d errors\n", ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002304#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002305 for (i = 0, k = 0; i < ctxt->errNr; i++) {
2306 err = &ctxt->errTab[i];
2307 if (k < MAX_ERROR) {
2308 for (j = 0; j < i; j++) {
2309 dup = &ctxt->errTab[j];
2310 if ((err->err == dup->err) && (err->node == dup->node) &&
2311 (xmlStrEqual(err->arg1, dup->arg1)) &&
2312 (xmlStrEqual(err->arg2, dup->arg2))) {
2313 goto skip;
2314 }
2315 }
2316 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2317 err->arg1, err->arg2);
2318 k++;
2319 }
2320 skip:
2321 if (err->flags & ERROR_IS_DUP) {
2322 if (err->arg1 != NULL)
2323 xmlFree((xmlChar *) err->arg1);
2324 err->arg1 = NULL;
2325 if (err->arg2 != NULL)
2326 xmlFree((xmlChar *) err->arg2);
2327 err->arg2 = NULL;
2328 err->flags = 0;
2329 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002330 }
2331 ctxt->errNr = 0;
2332}
Daniel Veillard4c004142003-10-07 11:33:24 +00002333
Daniel Veillard42f12e92003-03-07 18:32:59 +00002334/**
2335 * xmlRelaxNGAddValidError:
2336 * @ctxt: the validation context
2337 * @err: the error number
2338 * @arg1: the first argument
2339 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002340 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002341 *
2342 * Register a validation error, either generating it if it's sure
2343 * or stacking it for later handling if unsure.
2344 */
2345static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002346xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
2347 xmlRelaxNGValidErr err, const xmlChar * arg1,
2348 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002349{
Daniel Veillardb30ca312005-09-04 13:50:03 +00002350 if (ctxt == NULL)
2351 return;
2352 if (ctxt->flags & FLAGS_NOERROR)
Daniel Veillard4c004142003-10-07 11:33:24 +00002353 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002354
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002355#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002356 xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002357#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002358 /*
2359 * generate the error directly
2360 */
William M. Brack60929622004-03-27 17:54:18 +00002361 if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
2362 (ctxt->flags & FLAGS_NEGATIVE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002363 xmlNodePtr node, seq;
2364
2365 /*
2366 * Flush first any stacked error which might be the
2367 * real cause of the problem.
2368 */
2369 if (ctxt->errNr != 0)
2370 xmlRelaxNGDumpValidError(ctxt);
2371 if (ctxt->state != NULL) {
2372 node = ctxt->state->node;
2373 seq = ctxt->state->seq;
2374 } else {
2375 node = seq = NULL;
2376 }
Daniel Veillardec18c962009-08-26 18:37:43 +02002377 if ((node == NULL) && (seq == NULL)) {
2378 node = ctxt->pnode;
2379 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002380 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002381 }
2382 /*
2383 * Stack the error for later processing if needed
2384 */
2385 else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002386 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002387 }
2388}
2389
Daniel Veillard6eadf632003-01-23 18:29:16 +00002390
2391/************************************************************************
2392 * *
2393 * Type library hooks *
2394 * *
2395 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002396static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00002397 const xmlChar * str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002398
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002399/**
2400 * xmlRelaxNGSchemaTypeHave:
2401 * @data: data needed for the library
2402 * @type: the type name
2403 *
2404 * Check if the given type is provided by
2405 * the W3C XMLSchema Datatype library.
2406 *
2407 * Returns 1 if yes, 0 if no and -1 in case of error.
2408 */
2409static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002410xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
2411{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002412 xmlSchemaTypePtr typ;
2413
2414 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002415 return (-1);
2416 typ = xmlSchemaGetPredefinedType(type,
2417 BAD_CAST
2418 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002419 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002420 return (0);
2421 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002422}
2423
2424/**
2425 * xmlRelaxNGSchemaTypeCheck:
2426 * @data: data needed for the library
2427 * @type: the type name
2428 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002429 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002430 *
2431 * Check if the given type and value are validated by
2432 * the W3C XMLSchema Datatype library.
2433 *
2434 * Returns 1 if yes, 0 if no and -1 in case of error.
2435 */
2436static int
2437xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002438 const xmlChar * type,
2439 const xmlChar * value,
2440 void **result, xmlNodePtr node)
2441{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002442 xmlSchemaTypePtr typ;
2443 int ret;
2444
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002445 if ((type == NULL) || (value == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002446 return (-1);
2447 typ = xmlSchemaGetPredefinedType(type,
2448 BAD_CAST
2449 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002450 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002451 return (-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002452 ret = xmlSchemaValPredefTypeNode(typ, value,
Daniel Veillard4c004142003-10-07 11:33:24 +00002453 (xmlSchemaValPtr *) result, node);
2454 if (ret == 2) /* special ID error code */
2455 return (2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002456 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002457 return (1);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002458 if (ret > 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002459 return (0);
2460 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002461}
2462
2463/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002464 * xmlRelaxNGSchemaFacetCheck:
2465 * @data: data needed for the library
2466 * @type: the type name
2467 * @facet: the facet name
2468 * @val: the facet value
2469 * @strval: the string value
2470 * @value: the value to check
2471 *
2472 * Function provided by a type library to check a value facet
2473 *
2474 * Returns 1 if yes, 0 if no and -1 in case of error.
2475 */
2476static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002477xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
2478 const xmlChar * type, const xmlChar * facetname,
2479 const xmlChar * val, const xmlChar * strval,
2480 void *value)
2481{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002482 xmlSchemaFacetPtr facet;
2483 xmlSchemaTypePtr typ;
2484 int ret;
2485
2486 if ((type == NULL) || (strval == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002487 return (-1);
2488 typ = xmlSchemaGetPredefinedType(type,
2489 BAD_CAST
2490 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002491 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002492 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002493
2494 facet = xmlSchemaNewFacet();
2495 if (facet == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002496 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002497
Daniel Veillard4c004142003-10-07 11:33:24 +00002498 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002499 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002500 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002501 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002502 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002503 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002504 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002505 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002506 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002507 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002508 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002509 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002510 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002511 facet->type = XML_SCHEMA_FACET_PATTERN;
Daniel Veillard4c004142003-10-07 11:33:24 +00002512 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002513 facet->type = XML_SCHEMA_FACET_ENUMERATION;
Daniel Veillard4c004142003-10-07 11:33:24 +00002514 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002515 facet->type = XML_SCHEMA_FACET_WHITESPACE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002516 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002517 facet->type = XML_SCHEMA_FACET_LENGTH;
Daniel Veillard4c004142003-10-07 11:33:24 +00002518 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002519 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2520 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2521 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2522 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002523 xmlSchemaFreeFacet(facet);
2524 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002525 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00002526 facet->value = val;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002527 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2528 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002529 xmlSchemaFreeFacet(facet);
2530 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002531 }
2532 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2533 xmlSchemaFreeFacet(facet);
2534 if (ret != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002535 return (-1);
2536 return (0);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002537}
2538
2539/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002540 * xmlRelaxNGSchemaFreeValue:
2541 * @data: data needed for the library
2542 * @value: the value to free
2543 *
2544 * Function provided by a type library to free a Schemas value
2545 *
2546 * Returns 1 if yes, 0 if no and -1 in case of error.
2547 */
2548static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002549xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
2550{
Daniel Veillard80b19092003-03-28 13:29:53 +00002551 xmlSchemaFreeValue(value);
2552}
2553
2554/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002555 * xmlRelaxNGSchemaTypeCompare:
2556 * @data: data needed for the library
2557 * @type: the type name
2558 * @value1: the first value
2559 * @value2: the second value
2560 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002561 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002562 * Datatype library.
2563 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002564 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002565 */
2566static int
2567xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002568 const xmlChar * type,
2569 const xmlChar * value1,
2570 xmlNodePtr ctxt1,
2571 void *comp1,
2572 const xmlChar * value2, xmlNodePtr ctxt2)
2573{
Daniel Veillard80b19092003-03-28 13:29:53 +00002574 int ret;
2575 xmlSchemaTypePtr typ;
2576 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2577
2578 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002579 return (-1);
2580 typ = xmlSchemaGetPredefinedType(type,
2581 BAD_CAST
2582 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard80b19092003-03-28 13:29:53 +00002583 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002584 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002585 if (comp1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002586 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2587 if (ret != 0)
2588 return (-1);
2589 if (res1 == NULL)
2590 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002591 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002592 res1 = (xmlSchemaValPtr) comp1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002593 }
2594 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002595 if (ret != 0) {
Daniel Veillardf4644032005-06-13 11:41:31 +00002596 if ((comp1 == NULL) && (res1 != NULL))
2597 xmlSchemaFreeValue(res1);
Daniel Veillard4c004142003-10-07 11:33:24 +00002598 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002599 }
2600 if (res1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002601 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002602 }
2603 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002604 if (res1 != (xmlSchemaValPtr) comp1)
Daniel Veillard4c004142003-10-07 11:33:24 +00002605 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002606 xmlSchemaFreeValue(res2);
2607 if (ret == -2)
Daniel Veillard4c004142003-10-07 11:33:24 +00002608 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002609 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002610 return (1);
2611 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002612}
Daniel Veillard4c004142003-10-07 11:33:24 +00002613
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002614/**
2615 * xmlRelaxNGDefaultTypeHave:
2616 * @data: data needed for the library
2617 * @type: the type name
2618 *
2619 * Check if the given type is provided by
2620 * the default datatype library.
2621 *
2622 * Returns 1 if yes, 0 if no and -1 in case of error.
2623 */
2624static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002625xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
2626 const xmlChar * type)
2627{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002628 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002629 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002630 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002631 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002632 if (xmlStrEqual(type, BAD_CAST "token"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002633 return (1);
2634 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002635}
2636
2637/**
2638 * xmlRelaxNGDefaultTypeCheck:
2639 * @data: data needed for the library
2640 * @type: the type name
2641 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002642 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002643 *
2644 * Check if the given type and value are validated by
2645 * the default datatype library.
2646 *
2647 * Returns 1 if yes, 0 if no and -1 in case of error.
2648 */
2649static int
2650xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002651 const xmlChar * type ATTRIBUTE_UNUSED,
2652 const xmlChar * value ATTRIBUTE_UNUSED,
2653 void **result ATTRIBUTE_UNUSED,
2654 xmlNodePtr node ATTRIBUTE_UNUSED)
2655{
Daniel Veillardd4310742003-02-18 21:12:46 +00002656 if (value == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002657 return (-1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002658 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002659 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002660 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002661 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002662 }
2663
Daniel Veillard4c004142003-10-07 11:33:24 +00002664 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002665}
2666
2667/**
2668 * xmlRelaxNGDefaultTypeCompare:
2669 * @data: data needed for the library
2670 * @type: the type name
2671 * @value1: the first value
2672 * @value2: the second value
2673 *
2674 * Compare two values accordingly a type from the default
2675 * datatype library.
2676 *
2677 * Returns 1 if yes, 0 if no and -1 in case of error.
2678 */
2679static int
2680xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002681 const xmlChar * type,
2682 const xmlChar * value1,
2683 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2684 void *comp1 ATTRIBUTE_UNUSED,
2685 const xmlChar * value2,
2686 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
2687{
Daniel Veillardea3f3982003-01-26 19:45:18 +00002688 int ret = -1;
2689
2690 if (xmlStrEqual(type, BAD_CAST "string")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002691 ret = xmlStrEqual(value1, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002692 } else if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002693 if (!xmlStrEqual(value1, value2)) {
2694 xmlChar *nval, *nvalue;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002695
Daniel Veillard4c004142003-10-07 11:33:24 +00002696 /*
2697 * TODO: trivial optimizations are possible by
2698 * computing at compile-time
2699 */
2700 nval = xmlRelaxNGNormalize(NULL, value1);
2701 nvalue = xmlRelaxNGNormalize(NULL, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002702
Daniel Veillard4c004142003-10-07 11:33:24 +00002703 if ((nval == NULL) || (nvalue == NULL))
2704 ret = -1;
2705 else if (xmlStrEqual(nval, nvalue))
2706 ret = 1;
2707 else
2708 ret = 0;
2709 if (nval != NULL)
2710 xmlFree(nval);
2711 if (nvalue != NULL)
2712 xmlFree(nvalue);
2713 } else
2714 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002715 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002716 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002717}
Daniel Veillard4c004142003-10-07 11:33:24 +00002718
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002719static int xmlRelaxNGTypeInitialized = 0;
2720static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2721
2722/**
2723 * xmlRelaxNGFreeTypeLibrary:
2724 * @lib: the type library structure
2725 * @namespace: the URI bound to the library
2726 *
2727 * Free the structure associated to the type library
2728 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002729static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002730xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
Daniel Veillard4c004142003-10-07 11:33:24 +00002731 const xmlChar * namespace ATTRIBUTE_UNUSED)
2732{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002733 if (lib == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002734 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002735 if (lib->namespace != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002736 xmlFree((xmlChar *) lib->namespace);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002737 xmlFree(lib);
2738}
2739
2740/**
2741 * xmlRelaxNGRegisterTypeLibrary:
2742 * @namespace: the URI bound to the library
2743 * @data: data associated to the library
2744 * @have: the provide function
2745 * @check: the checking function
2746 * @comp: the comparison function
2747 *
2748 * Register a new type library
2749 *
2750 * Returns 0 in case of success and -1 in case of error.
2751 */
2752static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002753xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
2754 xmlRelaxNGTypeHave have,
2755 xmlRelaxNGTypeCheck check,
2756 xmlRelaxNGTypeCompare comp,
2757 xmlRelaxNGFacetCheck facet,
2758 xmlRelaxNGTypeFree freef)
2759{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002760 xmlRelaxNGTypeLibraryPtr lib;
2761 int ret;
2762
2763 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00002764 (check == NULL) || (comp == NULL))
2765 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002766 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002767 xmlGenericError(xmlGenericErrorContext,
2768 "Relax-NG types library '%s' already registered\n",
2769 namespace);
2770 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002771 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002772 lib =
2773 (xmlRelaxNGTypeLibraryPtr)
2774 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002775 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002776 xmlRngVErrMemory(NULL, "adding types library\n");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002777 return (-1);
2778 }
2779 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2780 lib->namespace = xmlStrdup(namespace);
2781 lib->data = data;
2782 lib->have = have;
2783 lib->comp = comp;
2784 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002785 lib->facet = facet;
2786 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002787 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2788 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002789 xmlGenericError(xmlGenericErrorContext,
2790 "Relax-NG types library failed to register '%s'\n",
2791 namespace);
2792 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2793 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002794 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002795 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002796}
2797
2798/**
2799 * xmlRelaxNGInitTypes:
2800 *
2801 * Initilize the default type libraries.
2802 *
2803 * Returns 0 in case of success and -1 in case of error.
2804 */
Daniel Veillarddd6d3002004-11-03 14:20:29 +00002805int
Daniel Veillard4c004142003-10-07 11:33:24 +00002806xmlRelaxNGInitTypes(void)
2807{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002808 if (xmlRelaxNGTypeInitialized != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002809 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002810 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2811 if (xmlRelaxNGRegisteredTypes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002812 xmlGenericError(xmlGenericErrorContext,
2813 "Failed to allocate sh table for Relax-NG types\n");
2814 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002815 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002816 xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2817 "http://www.w3.org/2001/XMLSchema-datatypes",
2818 NULL, xmlRelaxNGSchemaTypeHave,
2819 xmlRelaxNGSchemaTypeCheck,
2820 xmlRelaxNGSchemaTypeCompare,
2821 xmlRelaxNGSchemaFacetCheck,
2822 xmlRelaxNGSchemaFreeValue);
2823 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
2824 xmlRelaxNGDefaultTypeHave,
2825 xmlRelaxNGDefaultTypeCheck,
2826 xmlRelaxNGDefaultTypeCompare, NULL,
2827 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002828 xmlRelaxNGTypeInitialized = 1;
Daniel Veillard4c004142003-10-07 11:33:24 +00002829 return (0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002830}
2831
2832/**
2833 * xmlRelaxNGCleanupTypes:
2834 *
2835 * Cleanup the default Schemas type library associated to RelaxNG
2836 */
Daniel Veillard4c004142003-10-07 11:33:24 +00002837void
2838xmlRelaxNGCleanupTypes(void)
2839{
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002840 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002841 if (xmlRelaxNGTypeInitialized == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002842 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002843 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
Daniel Veillard4c004142003-10-07 11:33:24 +00002844 xmlRelaxNGFreeTypeLibrary);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002845 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002846}
2847
2848/************************************************************************
2849 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002850 * Compiling element content into regexp *
2851 * *
2852 * Sometime the element content can be compiled into a pure regexp, *
2853 * This allows a faster execution and streamability at that level *
2854 * *
2855 ************************************************************************/
2856
Daniel Veillard1ba2aca2009-08-31 16:47:39 +02002857/* from automata.c but not exported */
2858void xmlAutomataSetFlags(xmlAutomataPtr am, int flags);
2859
2860
Daniel Veillard52b48c72003-04-13 19:53:42 +00002861static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2862 xmlRelaxNGDefinePtr def);
2863
Daniel Veillard952379b2003-03-17 15:37:12 +00002864/**
2865 * xmlRelaxNGIsCompileable:
2866 * @define: the definition to check
2867 *
2868 * Check if a definition is nullable.
2869 *
2870 * Returns 1 if yes, 0 if no and -1 in case of error
2871 */
2872static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002873xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def)
2874{
Daniel Veillard52b48c72003-04-13 19:53:42 +00002875 int ret = -1;
2876
Daniel Veillard952379b2003-03-17 15:37:12 +00002877 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002878 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00002879 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002880 if ((def->type != XML_RELAXNG_ELEMENT) &&
2881 (def->dflags & IS_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002882 return (1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002883 if ((def->type != XML_RELAXNG_ELEMENT) &&
2884 (def->dflags & IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002885 return (0);
2886 switch (def->type) {
Daniel Veillard952379b2003-03-17 15:37:12 +00002887 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002888 ret = xmlRelaxNGIsCompileable(def->content);
2889 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002890 case XML_RELAXNG_TEXT:
Daniel Veillard952379b2003-03-17 15:37:12 +00002891 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00002892 ret = 1;
2893 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002894 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00002895 /*
2896 * Check if the element content is compileable
2897 */
2898 if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2899 ((def->dflags & IS_COMPILABLE) == 0)) {
2900 xmlRelaxNGDefinePtr list;
2901
2902 list = def->content;
2903 while (list != NULL) {
2904 ret = xmlRelaxNGIsCompileable(list);
2905 if (ret != 1)
2906 break;
2907 list = list->next;
2908 }
William M. Brack60929622004-03-27 17:54:18 +00002909 /*
2910 * Because the routine is recursive, we must guard against
2911 * discovering both COMPILABLE and NOT_COMPILABLE
2912 */
2913 if (ret == 0) {
2914 def->dflags &= ~IS_COMPILABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002915 def->dflags |= IS_NOT_COMPILABLE;
William M. Brack60929622004-03-27 17:54:18 +00002916 }
2917 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002918 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002919#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00002920 if (ret == 1) {
2921 xmlGenericError(xmlGenericErrorContext,
2922 "element content for %s is compilable\n",
2923 def->name);
2924 } else if (ret == 0) {
2925 xmlGenericError(xmlGenericErrorContext,
2926 "element content for %s is not compilable\n",
2927 def->name);
2928 } else {
2929 xmlGenericError(xmlGenericErrorContext,
2930 "Problem in RelaxNGIsCompileable for element %s\n",
2931 def->name);
2932 }
Daniel Veillardd94849b2003-07-28 13:02:24 +00002933#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002934 }
2935 /*
2936 * All elements return a compileable status unless they
2937 * are generic like anyName
2938 */
2939 if ((def->nameClass != NULL) || (def->name == NULL))
2940 ret = 0;
2941 else
2942 ret = 1;
2943 return (ret);
Daniel Veillard2134ab12003-07-23 19:56:29 +00002944 case XML_RELAXNG_REF:
2945 case XML_RELAXNG_EXTERNALREF:
2946 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00002947 if (def->depth == -20) {
2948 return (1);
2949 } else {
2950 xmlRelaxNGDefinePtr list;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002951
Daniel Veillard4c004142003-10-07 11:33:24 +00002952 def->depth = -20;
2953 list = def->content;
2954 while (list != NULL) {
2955 ret = xmlRelaxNGIsCompileable(list);
2956 if (ret != 1)
2957 break;
2958 list = list->next;
2959 }
2960 }
2961 break;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002962 case XML_RELAXNG_START:
Daniel Veillard952379b2003-03-17 15:37:12 +00002963 case XML_RELAXNG_OPTIONAL:
2964 case XML_RELAXNG_ZEROORMORE:
2965 case XML_RELAXNG_ONEORMORE:
2966 case XML_RELAXNG_CHOICE:
2967 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002968 case XML_RELAXNG_DEF:{
2969 xmlRelaxNGDefinePtr list;
Daniel Veillard952379b2003-03-17 15:37:12 +00002970
Daniel Veillard4c004142003-10-07 11:33:24 +00002971 list = def->content;
2972 while (list != NULL) {
2973 ret = xmlRelaxNGIsCompileable(list);
2974 if (ret != 1)
2975 break;
2976 list = list->next;
2977 }
2978 break;
2979 }
Daniel Veillard952379b2003-03-17 15:37:12 +00002980 case XML_RELAXNG_EXCEPT:
2981 case XML_RELAXNG_ATTRIBUTE:
2982 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002983 case XML_RELAXNG_DATATYPE:
2984 case XML_RELAXNG_LIST:
2985 case XML_RELAXNG_PARAM:
2986 case XML_RELAXNG_VALUE:
Daniel Veillard952379b2003-03-17 15:37:12 +00002987 case XML_RELAXNG_NOT_ALLOWED:
William M. Brack7e29c0a2004-04-02 09:07:22 +00002988 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00002989 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002990 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002991 if (ret == 0)
2992 def->dflags |= IS_NOT_COMPILABLE;
2993 if (ret == 1)
2994 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002995#ifdef DEBUG_COMPILE
2996 if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002997 xmlGenericError(xmlGenericErrorContext,
2998 "RelaxNGIsCompileable %s : true\n",
2999 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00003000 } else if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003001 xmlGenericError(xmlGenericErrorContext,
3002 "RelaxNGIsCompileable %s : false\n",
3003 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00003004 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003005 xmlGenericError(xmlGenericErrorContext,
3006 "Problem in RelaxNGIsCompileable %s\n",
3007 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00003008 }
3009#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00003010 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003011}
3012
3013/**
3014 * xmlRelaxNGCompile:
3015 * ctxt: the RelaxNG parser context
3016 * @define: the definition tree to compile
3017 *
3018 * Compile the set of definitions, it works recursively, till the
3019 * element boundaries, where it tries to compile the content if possible
3020 *
3021 * Returns 0 if success and -1 in case of error
3022 */
3023static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003024xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3025{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003026 int ret = 0;
3027 xmlRelaxNGDefinePtr list;
3028
Daniel Veillard4c004142003-10-07 11:33:24 +00003029 if ((ctxt == NULL) || (def == NULL))
3030 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003031
Daniel Veillard4c004142003-10-07 11:33:24 +00003032 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003033 case XML_RELAXNG_START:
3034 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003035 xmlAutomataPtr oldam = ctxt->am;
3036 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003037
3038 def->depth = -25;
3039
Daniel Veillard4c004142003-10-07 11:33:24 +00003040 list = def->content;
3041 ctxt->am = xmlNewAutomata();
3042 if (ctxt->am == NULL)
3043 return (-1);
Daniel Veillard1ba2aca2009-08-31 16:47:39 +02003044
3045 /*
3046 * assume identical strings but not same pointer are different
3047 * atoms, needed for non-determinism detection
3048 * That way if 2 elements with the same name are in a choice
3049 * branch the automata is found non-deterministic and
3050 * we fallback to the normal validation which does the right
3051 * thing of exploring both choices.
3052 */
3053 xmlAutomataSetFlags(ctxt->am, 1);
3054
Daniel Veillard4c004142003-10-07 11:33:24 +00003055 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3056 while (list != NULL) {
3057 xmlRelaxNGCompile(ctxt, list);
3058 list = list->next;
3059 }
3060 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3061 def->contModel = xmlAutomataCompile(ctxt->am);
3062 xmlRegexpIsDeterminist(def->contModel);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003063
Daniel Veillard4c004142003-10-07 11:33:24 +00003064 xmlFreeAutomata(ctxt->am);
3065 ctxt->state = oldstate;
3066 ctxt->am = oldam;
3067 }
3068 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003069 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003070 if ((ctxt->am != NULL) && (def->name != NULL)) {
3071 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
3072 ctxt->state, NULL,
3073 def->name, def->ns,
3074 def);
3075 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003076 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003077 xmlAutomataPtr oldam = ctxt->am;
3078 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003079
3080 def->depth = -25;
3081
Daniel Veillard4c004142003-10-07 11:33:24 +00003082 list = def->content;
3083 ctxt->am = xmlNewAutomata();
3084 if (ctxt->am == NULL)
3085 return (-1);
Daniel Veillard1ba2aca2009-08-31 16:47:39 +02003086 xmlAutomataSetFlags(ctxt->am, 1);
Daniel Veillard4c004142003-10-07 11:33:24 +00003087 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3088 while (list != NULL) {
3089 xmlRelaxNGCompile(ctxt, list);
3090 list = list->next;
3091 }
3092 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3093 def->contModel = xmlAutomataCompile(ctxt->am);
3094 if (!xmlRegexpIsDeterminist(def->contModel)) {
Daniel Veillard1ba2aca2009-08-31 16:47:39 +02003095#ifdef DEBUG_COMPILE
3096 xmlGenericError(xmlGenericErrorContext,
3097 "Content model not determinist %s\n",
3098 def->name);
3099#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00003100 /*
3101 * we can only use the automata if it is determinist
3102 */
3103 xmlRegFreeRegexp(def->contModel);
3104 def->contModel = NULL;
3105 }
3106 xmlFreeAutomata(ctxt->am);
3107 ctxt->state = oldstate;
3108 ctxt->am = oldam;
3109 } else {
3110 xmlAutomataPtr oldam = ctxt->am;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003111
Daniel Veillard4c004142003-10-07 11:33:24 +00003112 /*
3113 * we can't build the content model for this element content
3114 * but it still might be possible to build it for some of its
3115 * children, recurse.
3116 */
3117 ret = xmlRelaxNGTryCompile(ctxt, def);
3118 ctxt->am = oldam;
3119 }
3120 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003121 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003122 ret = xmlRelaxNGCompile(ctxt, def->content);
3123 break;
3124 case XML_RELAXNG_OPTIONAL:{
3125 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003126
Daniel Veillardfd780772009-08-26 18:35:29 +02003127 list = def->content;
3128 while (list != NULL) {
3129 xmlRelaxNGCompile(ctxt, list);
3130 list = list->next;
3131 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003132 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3133 break;
3134 }
3135 case XML_RELAXNG_ZEROORMORE:{
3136 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003137
Daniel Veillard4c004142003-10-07 11:33:24 +00003138 ctxt->state =
3139 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3140 oldstate = ctxt->state;
3141 list = def->content;
3142 while (list != NULL) {
3143 xmlRelaxNGCompile(ctxt, list);
3144 list = list->next;
3145 }
3146 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3147 ctxt->state =
3148 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3149 break;
3150 }
3151 case XML_RELAXNG_ONEORMORE:{
3152 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003153
Daniel Veillard4c004142003-10-07 11:33:24 +00003154 list = def->content;
3155 while (list != NULL) {
3156 xmlRelaxNGCompile(ctxt, list);
3157 list = list->next;
3158 }
3159 oldstate = ctxt->state;
3160 list = def->content;
3161 while (list != NULL) {
3162 xmlRelaxNGCompile(ctxt, list);
3163 list = list->next;
3164 }
3165 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3166 ctxt->state =
3167 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3168 break;
3169 }
3170 case XML_RELAXNG_CHOICE:{
3171 xmlAutomataStatePtr target = NULL;
3172 xmlAutomataStatePtr oldstate = ctxt->state;
3173
3174 list = def->content;
3175 while (list != NULL) {
3176 ctxt->state = oldstate;
3177 ret = xmlRelaxNGCompile(ctxt, list);
3178 if (ret != 0)
3179 break;
3180 if (target == NULL)
3181 target = ctxt->state;
3182 else {
3183 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3184 target);
3185 }
3186 list = list->next;
3187 }
3188 ctxt->state = target;
3189
3190 break;
3191 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003192 case XML_RELAXNG_REF:
3193 case XML_RELAXNG_EXTERNALREF:
3194 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00003195 case XML_RELAXNG_GROUP:
3196 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003197 list = def->content;
3198 while (list != NULL) {
3199 ret = xmlRelaxNGCompile(ctxt, list);
3200 if (ret != 0)
3201 break;
3202 list = list->next;
3203 }
3204 break;
3205 case XML_RELAXNG_TEXT:{
3206 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003207
Daniel Veillard4c004142003-10-07 11:33:24 +00003208 ctxt->state =
3209 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3210 oldstate = ctxt->state;
3211 xmlRelaxNGCompile(ctxt, def->content);
3212 xmlAutomataNewTransition(ctxt->am, ctxt->state,
3213 ctxt->state, BAD_CAST "#text",
3214 NULL);
3215 ctxt->state =
3216 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3217 break;
3218 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003219 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00003220 ctxt->state =
3221 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3222 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003223 case XML_RELAXNG_EXCEPT:
3224 case XML_RELAXNG_ATTRIBUTE:
3225 case XML_RELAXNG_INTERLEAVE:
3226 case XML_RELAXNG_NOT_ALLOWED:
3227 case XML_RELAXNG_DATATYPE:
3228 case XML_RELAXNG_LIST:
3229 case XML_RELAXNG_PARAM:
3230 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003231 /* This should not happen and generate an internal error */
3232 fprintf(stderr, "RNG internal error trying to compile %s\n",
3233 xmlRelaxNGDefName(def));
3234 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003235 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003236 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003237}
3238
3239/**
3240 * xmlRelaxNGTryCompile:
3241 * ctxt: the RelaxNG parser context
3242 * @define: the definition tree to compile
3243 *
3244 * Try to compile the set of definitions, it works recursively,
3245 * possibly ignoring parts which cannot be compiled.
3246 *
3247 * Returns 0 if success and -1 in case of error
3248 */
3249static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003250xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3251{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003252 int ret = 0;
3253 xmlRelaxNGDefinePtr list;
3254
Daniel Veillard4c004142003-10-07 11:33:24 +00003255 if ((ctxt == NULL) || (def == NULL))
3256 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003257
3258 if ((def->type == XML_RELAXNG_START) ||
3259 (def->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003260 ret = xmlRelaxNGIsCompileable(def);
3261 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3262 ctxt->am = NULL;
3263 ret = xmlRelaxNGCompile(ctxt, def);
Daniel Veillard2134ab12003-07-23 19:56:29 +00003264#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00003265 if (ret == 0) {
3266 if (def->type == XML_RELAXNG_START)
3267 xmlGenericError(xmlGenericErrorContext,
3268 "compiled the start\n");
3269 else
3270 xmlGenericError(xmlGenericErrorContext,
3271 "compiled element %s\n", def->name);
3272 } else {
3273 if (def->type == XML_RELAXNG_START)
3274 xmlGenericError(xmlGenericErrorContext,
3275 "failed to compile the start\n");
3276 else
3277 xmlGenericError(xmlGenericErrorContext,
3278 "failed to compile element %s\n",
3279 def->name);
3280 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003281#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00003282 return (ret);
3283 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003284 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003285 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003286 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003287 ret = xmlRelaxNGTryCompile(ctxt, def->content);
3288 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003289 case XML_RELAXNG_TEXT:
3290 case XML_RELAXNG_DATATYPE:
3291 case XML_RELAXNG_LIST:
3292 case XML_RELAXNG_PARAM:
3293 case XML_RELAXNG_VALUE:
3294 case XML_RELAXNG_EMPTY:
3295 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003296 ret = 0;
3297 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003298 case XML_RELAXNG_OPTIONAL:
3299 case XML_RELAXNG_ZEROORMORE:
3300 case XML_RELAXNG_ONEORMORE:
3301 case XML_RELAXNG_CHOICE:
3302 case XML_RELAXNG_GROUP:
3303 case XML_RELAXNG_DEF:
Daniel Veillard2134ab12003-07-23 19:56:29 +00003304 case XML_RELAXNG_START:
3305 case XML_RELAXNG_REF:
3306 case XML_RELAXNG_EXTERNALREF:
3307 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003308 list = def->content;
3309 while (list != NULL) {
3310 ret = xmlRelaxNGTryCompile(ctxt, list);
3311 if (ret != 0)
3312 break;
3313 list = list->next;
3314 }
3315 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003316 case XML_RELAXNG_EXCEPT:
3317 case XML_RELAXNG_ATTRIBUTE:
3318 case XML_RELAXNG_INTERLEAVE:
3319 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00003320 ret = 0;
3321 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003322 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003323 return (ret);
Daniel Veillard952379b2003-03-17 15:37:12 +00003324}
3325
3326/************************************************************************
3327 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00003328 * Parsing functions *
3329 * *
3330 ************************************************************************/
3331
Daniel Veillard4c004142003-10-07 11:33:24 +00003332static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3333 ctxt, xmlNodePtr node);
3334static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3335 ctxt, xmlNodePtr node);
3336static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3337 ctxt, xmlNodePtr nodes,
3338 int group);
3339static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3340 ctxt, xmlNodePtr node);
3341static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3342 xmlNodePtr node);
3343static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3344 xmlNodePtr nodes);
3345static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3346 ctxt, xmlNodePtr node,
3347 xmlRelaxNGDefinePtr
3348 def);
3349static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3350 ctxt, xmlNodePtr nodes);
3351static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3352 xmlRelaxNGDefinePtr define,
3353 xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003354
3355
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003356#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00003357
3358/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003359 * xmlRelaxNGIsNullable:
3360 * @define: the definition to verify
3361 *
3362 * Check if a definition is nullable.
3363 *
3364 * Returns 1 if yes, 0 if no and -1 in case of error
3365 */
3366static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003367xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3368{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003369 int ret;
Daniel Veillard4c004142003-10-07 11:33:24 +00003370
Daniel Veillardfd573f12003-03-16 17:52:32 +00003371 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003372 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003373
Daniel Veillarde063f482003-03-21 16:53:17 +00003374 if (define->dflags & IS_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003375 return (1);
Daniel Veillarde063f482003-03-21 16:53:17 +00003376 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003377 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003378 switch (define->type) {
3379 case XML_RELAXNG_EMPTY:
3380 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003381 ret = 1;
3382 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003383 case XML_RELAXNG_NOOP:
3384 case XML_RELAXNG_DEF:
3385 case XML_RELAXNG_REF:
3386 case XML_RELAXNG_EXTERNALREF:
3387 case XML_RELAXNG_PARENTREF:
3388 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003389 ret = xmlRelaxNGIsNullable(define->content);
3390 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003391 case XML_RELAXNG_EXCEPT:
3392 case XML_RELAXNG_NOT_ALLOWED:
3393 case XML_RELAXNG_ELEMENT:
3394 case XML_RELAXNG_DATATYPE:
3395 case XML_RELAXNG_PARAM:
3396 case XML_RELAXNG_VALUE:
3397 case XML_RELAXNG_LIST:
3398 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003399 ret = 0;
3400 break;
3401 case XML_RELAXNG_CHOICE:{
3402 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003403
Daniel Veillard4c004142003-10-07 11:33:24 +00003404 while (list != NULL) {
3405 ret = xmlRelaxNGIsNullable(list);
3406 if (ret != 0)
3407 goto done;
3408 list = list->next;
3409 }
3410 ret = 0;
3411 break;
3412 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003413 case XML_RELAXNG_START:
3414 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003415 case XML_RELAXNG_GROUP:{
3416 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003417
Daniel Veillard4c004142003-10-07 11:33:24 +00003418 while (list != NULL) {
3419 ret = xmlRelaxNGIsNullable(list);
3420 if (ret != 1)
3421 goto done;
3422 list = list->next;
3423 }
3424 return (1);
3425 }
3426 default:
3427 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003428 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003429 done:
Daniel Veillardfd573f12003-03-16 17:52:32 +00003430 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003431 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003432 if (ret == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00003433 define->dflags |= IS_NULLABLE;
3434 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003435}
3436
3437/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003438 * xmlRelaxNGIsBlank:
3439 * @str: a string
3440 *
3441 * Check if a string is ignorable c.f. 4.2. Whitespace
3442 *
3443 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3444 */
3445static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003446xmlRelaxNGIsBlank(xmlChar * str)
3447{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003448 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003449 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003450 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003451 if (!(IS_BLANK_CH(*str)))
Daniel Veillard4c004142003-10-07 11:33:24 +00003452 return (0);
3453 str++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003454 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003455 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003456}
3457
Daniel Veillard6eadf632003-01-23 18:29:16 +00003458/**
3459 * xmlRelaxNGGetDataTypeLibrary:
3460 * @ctxt: a Relax-NG parser context
3461 * @node: the current data or value element
3462 *
3463 * Applies algorithm from 4.3. datatypeLibrary attribute
3464 *
3465 * Returns the datatypeLibary value or NULL if not found
3466 */
3467static xmlChar *
3468xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00003469 xmlNodePtr node)
3470{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003471 xmlChar *ret, *escape;
3472
Daniel Veillard6eadf632003-01-23 18:29:16 +00003473 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003474 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3475 if (ret != NULL) {
3476 if (ret[0] == 0) {
3477 xmlFree(ret);
3478 return (NULL);
3479 }
3480 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3481 if (escape == NULL) {
3482 return (ret);
3483 }
3484 xmlFree(ret);
3485 return (escape);
3486 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003487 }
3488 node = node->parent;
3489 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003490 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3491 if (ret != NULL) {
3492 if (ret[0] == 0) {
3493 xmlFree(ret);
3494 return (NULL);
3495 }
3496 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3497 if (escape == NULL) {
3498 return (ret);
3499 }
3500 xmlFree(ret);
3501 return (escape);
3502 }
3503 node = node->parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003504 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003505 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003506}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003507
3508/**
Daniel Veillardedc91922003-01-26 00:52:04 +00003509 * xmlRelaxNGParseValue:
3510 * @ctxt: a Relax-NG parser context
3511 * @node: the data node.
3512 *
3513 * parse the content of a RelaxNG value node.
3514 *
3515 * Returns the definition pointer or NULL in case of error
3516 */
3517static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003518xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3519{
Daniel Veillardedc91922003-01-26 00:52:04 +00003520 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00003521 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00003522 xmlChar *type;
3523 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003524 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00003525
Daniel Veillardfd573f12003-03-16 17:52:32 +00003526 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003527 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003528 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003529 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00003530
3531 type = xmlGetProp(node, BAD_CAST "type");
3532 if (type != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003533 xmlRelaxNGNormExtSpace(type);
3534 if (xmlValidateNCName(type, 0)) {
3535 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3536 "value type '%s' is not an NCName\n", type, NULL);
3537 }
3538 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3539 if (library == NULL)
3540 library =
3541 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillardedc91922003-01-26 00:52:04 +00003542
Daniel Veillard4c004142003-10-07 11:33:24 +00003543 def->name = type;
3544 def->ns = library;
Daniel Veillardedc91922003-01-26 00:52:04 +00003545
Daniel Veillard4c004142003-10-07 11:33:24 +00003546 lib = (xmlRelaxNGTypeLibraryPtr)
3547 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3548 if (lib == NULL) {
3549 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3550 "Use of unregistered type library '%s'\n", library,
3551 NULL);
3552 def->data = NULL;
3553 } else {
3554 def->data = lib;
3555 if (lib->have == NULL) {
3556 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3557 "Internal error with type library '%s': no 'have'\n",
3558 library, NULL);
3559 } else {
3560 success = lib->have(lib->data, def->name);
3561 if (success != 1) {
3562 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3563 "Error type '%s' is not exported by type library '%s'\n",
3564 def->name, library);
3565 }
3566 }
3567 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003568 }
3569 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003570 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00003571 } else if (((node->children->type != XML_TEXT_NODE) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00003572 (node->children->type != XML_CDATA_SECTION_NODE)) ||
3573 (node->children->next != NULL)) {
3574 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3575 "Expecting a single text value for <value>content\n",
3576 NULL, NULL);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003577 } else if (def != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003578 def->value = xmlNodeGetContent(node);
3579 if (def->value == NULL) {
3580 xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3581 "Element <value> has no content\n", NULL, NULL);
3582 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3583 void *val = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003584
Daniel Veillard4c004142003-10-07 11:33:24 +00003585 success =
3586 lib->check(lib->data, def->name, def->value, &val, node);
3587 if (success != 1) {
3588 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3589 "Value '%s' is not acceptable for type '%s'\n",
3590 def->value, def->name);
3591 } else {
3592 if (val != NULL)
3593 def->attrs = val;
3594 }
3595 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003596 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003597 return (def);
Daniel Veillardedc91922003-01-26 00:52:04 +00003598}
3599
3600/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003601 * xmlRelaxNGParseData:
3602 * @ctxt: a Relax-NG parser context
3603 * @node: the data node.
3604 *
3605 * parse the content of a RelaxNG data node.
3606 *
3607 * Returns the definition pointer or NULL in case of error
3608 */
3609static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003610xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3611{
Daniel Veillard14b56432006-03-09 18:41:40 +00003612 xmlRelaxNGDefinePtr def = NULL, except;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003613 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003614 xmlRelaxNGTypeLibraryPtr lib;
3615 xmlChar *type;
3616 xmlChar *library;
3617 xmlNodePtr content;
3618 int tmp;
3619
3620 type = xmlGetProp(node, BAD_CAST "type");
3621 if (type == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003622 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3623 NULL);
3624 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003625 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003626 xmlRelaxNGNormExtSpace(type);
3627 if (xmlValidateNCName(type, 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003628 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3629 "data type '%s' is not an NCName\n", type, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003630 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003631 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3632 if (library == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003633 library =
3634 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003635
Daniel Veillardfd573f12003-03-16 17:52:32 +00003636 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003637 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003638 xmlFree(type);
3639 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003640 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003641 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003642 def->name = type;
3643 def->ns = library;
3644
3645 lib = (xmlRelaxNGTypeLibraryPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00003646 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003647 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003648 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3649 "Use of unregistered type library '%s'\n", library,
3650 NULL);
3651 def->data = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003652 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003653 def->data = lib;
3654 if (lib->have == NULL) {
3655 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3656 "Internal error with type library '%s': no 'have'\n",
3657 library, NULL);
3658 } else {
3659 tmp = lib->have(lib->data, def->name);
3660 if (tmp != 1) {
3661 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3662 "Error type '%s' is not exported by type library '%s'\n",
3663 def->name, library);
3664 } else
3665 if ((xmlStrEqual
3666 (library,
3667 BAD_CAST
3668 "http://www.w3.org/2001/XMLSchema-datatypes"))
3669 && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3670 || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3671 ctxt->idref = 1;
3672 }
3673 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003674 }
3675 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003676
3677 /*
3678 * Handle optional params
3679 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003680 while (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003681 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3682 break;
3683 if (xmlStrEqual(library,
3684 BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3685 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3686 "Type library '%s' does not allow type parameters\n",
3687 library, NULL);
3688 content = content->next;
3689 while ((content != NULL) &&
3690 (xmlStrEqual(content->name, BAD_CAST "param")))
3691 content = content->next;
3692 } else {
3693 param = xmlRelaxNGNewDefine(ctxt, node);
3694 if (param != NULL) {
3695 param->type = XML_RELAXNG_PARAM;
3696 param->name = xmlGetProp(content, BAD_CAST "name");
3697 if (param->name == NULL) {
3698 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3699 "param has no name\n", NULL, NULL);
3700 }
3701 param->value = xmlNodeGetContent(content);
3702 if (lastparam == NULL) {
3703 def->attrs = lastparam = param;
3704 } else {
3705 lastparam->next = param;
3706 lastparam = param;
3707 }
3708 if (lib != NULL) {
3709 }
3710 }
3711 content = content->next;
3712 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003713 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003714 /*
3715 * Handle optional except
3716 */
Daniel Veillard4c004142003-10-07 11:33:24 +00003717 if ((content != NULL)
3718 && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3719 xmlNodePtr child;
Daniel Veillard14b56432006-03-09 18:41:40 +00003720 xmlRelaxNGDefinePtr tmp2, last = NULL;
Daniel Veillard416589a2003-02-17 17:25:42 +00003721
Daniel Veillard4c004142003-10-07 11:33:24 +00003722 except = xmlRelaxNGNewDefine(ctxt, node);
3723 if (except == NULL) {
3724 return (def);
3725 }
3726 except->type = XML_RELAXNG_EXCEPT;
3727 child = content->children;
Daniel Veillard14b56432006-03-09 18:41:40 +00003728 def->content = except;
Daniel Veillard4c004142003-10-07 11:33:24 +00003729 if (child == NULL) {
3730 xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3731 "except has no content\n", NULL, NULL);
3732 }
3733 while (child != NULL) {
3734 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3735 if (tmp2 != NULL) {
Daniel Veillard14b56432006-03-09 18:41:40 +00003736 if (last == NULL) {
3737 except->content = last = tmp2;
Daniel Veillard4c004142003-10-07 11:33:24 +00003738 } else {
Daniel Veillard14b56432006-03-09 18:41:40 +00003739 last->next = tmp2;
3740 last = tmp2;
Daniel Veillard4c004142003-10-07 11:33:24 +00003741 }
3742 }
3743 child = child->next;
3744 }
3745 content = content->next;
Daniel Veillard416589a2003-02-17 17:25:42 +00003746 }
3747 /*
3748 * Check there is no unhandled data
3749 */
3750 if (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003751 xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3752 "Element data has unexpected content %s\n",
3753 content->name, NULL);
Daniel Veillard416589a2003-02-17 17:25:42 +00003754 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003755
Daniel Veillard4c004142003-10-07 11:33:24 +00003756 return (def);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003757}
3758
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003759static const xmlChar *invalidName = BAD_CAST "\1";
3760
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003761/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003762 * xmlRelaxNGCompareNameClasses:
3763 * @defs1: the first element/attribute defs
3764 * @defs2: the second element/attribute defs
3765 * @name: the restriction on the name
3766 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003767 *
3768 * Compare the 2 lists of element definitions. The comparison is
3769 * that if both lists do not accept the same QNames, it returns 1
3770 * If the 2 lists can accept the same QName the comparison returns 0
3771 *
3772 * Returns 1 disttinct, 0 if equal
3773 */
3774static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003775xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
Daniel Veillard4c004142003-10-07 11:33:24 +00003776 xmlRelaxNGDefinePtr def2)
3777{
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003778 int ret = 1;
3779 xmlNode node;
3780 xmlNs ns;
3781 xmlRelaxNGValidCtxt ctxt;
Daniel Veillard4c004142003-10-07 11:33:24 +00003782
Daniel Veillard42f12e92003-03-07 18:32:59 +00003783 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3784
Daniel Veillardb30ca312005-09-04 13:50:03 +00003785 ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR;
3786
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003787 if ((def1->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003788 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3789 if (def2->type == XML_RELAXNG_TEXT)
3790 return (1);
3791 if (def1->name != NULL) {
3792 node.name = def1->name;
3793 } else {
3794 node.name = invalidName;
3795 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003796 if (def1->ns != NULL) {
3797 if (def1->ns[0] == 0) {
3798 node.ns = NULL;
3799 } else {
William M. Bracka74a6ff2004-04-02 14:03:22 +00003800 node.ns = &ns;
Daniel Veillard4c004142003-10-07 11:33:24 +00003801 ns.href = def1->ns;
3802 }
3803 } else {
William M. Bracka74a6ff2004-04-02 14:03:22 +00003804 node.ns = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00003805 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003806 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003807 if (def1->nameClass != NULL) {
3808 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3809 } else {
3810 ret = 0;
3811 }
3812 } else {
3813 ret = 1;
3814 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003815 } else if (def1->type == XML_RELAXNG_TEXT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003816 if (def2->type == XML_RELAXNG_TEXT)
3817 return (0);
3818 return (1);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003819 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003820 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003821 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003822 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003823 }
3824 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003825 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003826 if ((def2->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003827 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3828 if (def2->name != NULL) {
3829 node.name = def2->name;
3830 } else {
3831 node.name = invalidName;
3832 }
3833 node.ns = &ns;
3834 if (def2->ns != NULL) {
3835 if (def2->ns[0] == 0) {
3836 node.ns = NULL;
3837 } else {
3838 ns.href = def2->ns;
3839 }
3840 } else {
3841 ns.href = invalidName;
3842 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003843 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003844 if (def2->nameClass != NULL) {
3845 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3846 } else {
3847 ret = 0;
3848 }
3849 } else {
3850 ret = 1;
3851 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003852 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003853 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003854 }
3855
Daniel Veillard4c004142003-10-07 11:33:24 +00003856 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003857}
3858
3859/**
3860 * xmlRelaxNGCompareElemDefLists:
3861 * @ctxt: a Relax-NG parser context
3862 * @defs1: the first list of element/attribute defs
3863 * @defs2: the second list of element/attribute defs
3864 *
3865 * Compare the 2 lists of element or attribute definitions. The comparison
3866 * is that if both lists do not accept the same QNames, it returns 1
3867 * If the 2 lists can accept the same QName the comparison returns 0
3868 *
3869 * Returns 1 disttinct, 0 if equal
3870 */
3871static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003872xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3873 ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3874 xmlRelaxNGDefinePtr * def2)
3875{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003876 xmlRelaxNGDefinePtr *basedef2 = def2;
Daniel Veillard4c004142003-10-07 11:33:24 +00003877
Daniel Veillard154877e2003-01-30 12:17:05 +00003878 if ((def1 == NULL) || (def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003879 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003880 if ((*def1 == NULL) || (*def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003881 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003882 while (*def1 != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003883 while ((*def2) != NULL) {
3884 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3885 return (0);
3886 def2++;
3887 }
3888 def2 = basedef2;
3889 def1++;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003890 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003891 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003892}
3893
3894/**
Daniel Veillardce192eb2003-04-16 15:58:05 +00003895 * xmlRelaxNGGenerateAttributes:
3896 * @ctxt: a Relax-NG parser context
3897 * @def: the definition definition
3898 *
3899 * Check if the definition can only generate attributes
3900 *
3901 * Returns 1 if yes, 0 if no and -1 in case of error.
3902 */
3903static int
3904xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003905 xmlRelaxNGDefinePtr def)
3906{
Daniel Veillardce192eb2003-04-16 15:58:05 +00003907 xmlRelaxNGDefinePtr parent, cur, tmp;
3908
3909 /*
3910 * Don't run that check in case of error. Infinite recursion
3911 * becomes possible.
3912 */
3913 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003914 return (-1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003915
3916 parent = NULL;
3917 cur = def;
3918 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003919 if ((cur->type == XML_RELAXNG_ELEMENT) ||
3920 (cur->type == XML_RELAXNG_TEXT) ||
3921 (cur->type == XML_RELAXNG_DATATYPE) ||
3922 (cur->type == XML_RELAXNG_PARAM) ||
3923 (cur->type == XML_RELAXNG_LIST) ||
3924 (cur->type == XML_RELAXNG_VALUE) ||
3925 (cur->type == XML_RELAXNG_EMPTY))
3926 return (0);
3927 if ((cur->type == XML_RELAXNG_CHOICE) ||
3928 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3929 (cur->type == XML_RELAXNG_GROUP) ||
3930 (cur->type == XML_RELAXNG_ONEORMORE) ||
3931 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3932 (cur->type == XML_RELAXNG_OPTIONAL) ||
3933 (cur->type == XML_RELAXNG_PARENTREF) ||
3934 (cur->type == XML_RELAXNG_EXTERNALREF) ||
3935 (cur->type == XML_RELAXNG_REF) ||
3936 (cur->type == XML_RELAXNG_DEF)) {
3937 if (cur->content != NULL) {
3938 parent = cur;
3939 cur = cur->content;
3940 tmp = cur;
3941 while (tmp != NULL) {
3942 tmp->parent = parent;
3943 tmp = tmp->next;
3944 }
3945 continue;
3946 }
3947 }
3948 if (cur == def)
3949 break;
3950 if (cur->next != NULL) {
3951 cur = cur->next;
3952 continue;
3953 }
3954 do {
3955 cur = cur->parent;
3956 if (cur == NULL)
3957 break;
3958 if (cur == def)
3959 return (1);
3960 if (cur->next != NULL) {
3961 cur = cur->next;
3962 break;
3963 }
3964 } while (cur != NULL);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003965 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003966 return (1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003967}
Daniel Veillard4c004142003-10-07 11:33:24 +00003968
Daniel Veillardce192eb2003-04-16 15:58:05 +00003969/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003970 * xmlRelaxNGGetElements:
3971 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003972 * @def: the definition definition
3973 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003974 *
3975 * Compute the list of top elements a definition can generate
3976 *
3977 * Returns a list of elements or NULL if none was found.
3978 */
3979static xmlRelaxNGDefinePtr *
3980xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003981 xmlRelaxNGDefinePtr def, int eora)
3982{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003983 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003984 int len = 0;
3985 int max = 0;
3986
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003987 /*
3988 * Don't run that check in case of error. Infinite recursion
3989 * becomes possible.
3990 */
3991 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003992 return (NULL);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003993
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003994 parent = NULL;
3995 cur = def;
3996 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003997 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3998 (cur->type == XML_RELAXNG_TEXT))) ||
3999 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
4000 if (ret == NULL) {
4001 max = 10;
4002 ret = (xmlRelaxNGDefinePtr *)
4003 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
4004 if (ret == NULL) {
4005 xmlRngPErrMemory(ctxt, "getting element list\n");
4006 return (NULL);
4007 }
4008 } else if (max <= len) {
Daniel Veillard079f6a72004-09-23 13:15:03 +00004009 xmlRelaxNGDefinePtr *temp;
4010
Daniel Veillard4c004142003-10-07 11:33:24 +00004011 max *= 2;
Daniel Veillard079f6a72004-09-23 13:15:03 +00004012 temp = xmlRealloc(ret,
Daniel Veillard4c004142003-10-07 11:33:24 +00004013 (max + 1) * sizeof(xmlRelaxNGDefinePtr));
Daniel Veillard079f6a72004-09-23 13:15:03 +00004014 if (temp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004015 xmlRngPErrMemory(ctxt, "getting element list\n");
Daniel Veillard079f6a72004-09-23 13:15:03 +00004016 xmlFree(ret);
Daniel Veillard4c004142003-10-07 11:33:24 +00004017 return (NULL);
4018 }
Daniel Veillard079f6a72004-09-23 13:15:03 +00004019 ret = temp;
Daniel Veillard4c004142003-10-07 11:33:24 +00004020 }
4021 ret[len++] = cur;
4022 ret[len] = NULL;
4023 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
4024 (cur->type == XML_RELAXNG_INTERLEAVE) ||
4025 (cur->type == XML_RELAXNG_GROUP) ||
4026 (cur->type == XML_RELAXNG_ONEORMORE) ||
4027 (cur->type == XML_RELAXNG_ZEROORMORE) ||
4028 (cur->type == XML_RELAXNG_OPTIONAL) ||
4029 (cur->type == XML_RELAXNG_PARENTREF) ||
4030 (cur->type == XML_RELAXNG_REF) ||
William M. Brack236c8c02004-03-20 11:32:36 +00004031 (cur->type == XML_RELAXNG_DEF) ||
4032 (cur->type == XML_RELAXNG_EXTERNALREF)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004033 /*
4034 * Don't go within elements or attributes or string values.
4035 * Just gather the element top list
4036 */
4037 if (cur->content != NULL) {
4038 parent = cur;
4039 cur = cur->content;
4040 tmp = cur;
4041 while (tmp != NULL) {
4042 tmp->parent = parent;
4043 tmp = tmp->next;
4044 }
4045 continue;
4046 }
4047 }
4048 if (cur == def)
4049 break;
4050 if (cur->next != NULL) {
4051 cur = cur->next;
4052 continue;
4053 }
4054 do {
4055 cur = cur->parent;
4056 if (cur == NULL)
4057 break;
4058 if (cur == def)
4059 return (ret);
4060 if (cur->next != NULL) {
4061 cur = cur->next;
4062 break;
4063 }
4064 } while (cur != NULL);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004065 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004066 return (ret);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004067}
Daniel Veillard4c004142003-10-07 11:33:24 +00004068
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004069/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004070 * xmlRelaxNGCheckChoiceDeterminism:
4071 * @ctxt: a Relax-NG parser context
4072 * @def: the choice definition
4073 *
4074 * Also used to find indeterministic pattern in choice
4075 */
4076static void
4077xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004078 xmlRelaxNGDefinePtr def)
4079{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004080 xmlRelaxNGDefinePtr **list;
4081 xmlRelaxNGDefinePtr cur;
4082 int nbchild = 0, i, j, ret;
4083 int is_nullable = 0;
4084 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004085 xmlHashTablePtr triage = NULL;
4086 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004087
Daniel Veillard4c004142003-10-07 11:33:24 +00004088 if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
4089 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004090
Daniel Veillarde063f482003-03-21 16:53:17 +00004091 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004092 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004093
Daniel Veillardfd573f12003-03-16 17:52:32 +00004094 /*
4095 * Don't run that check in case of error. Infinite recursion
4096 * becomes possible.
4097 */
4098 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004099 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004100
4101 is_nullable = xmlRelaxNGIsNullable(def);
4102
4103 cur = def->content;
4104 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004105 nbchild++;
4106 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004107 }
4108
4109 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004110 sizeof(xmlRelaxNGDefinePtr
4111 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004112 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004113 xmlRngPErrMemory(ctxt, "building choice\n");
4114 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004115 }
4116 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004117 /*
4118 * a bit strong but safe
4119 */
4120 if (is_nullable == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004121 triage = xmlHashCreate(10);
Daniel Veillarde063f482003-03-21 16:53:17 +00004122 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004123 is_triable = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004124 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004125 cur = def->content;
4126 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004127 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4128 if ((list[i] == NULL) || (list[i][0] == NULL)) {
4129 is_triable = 0;
4130 } else if (is_triable == 1) {
4131 xmlRelaxNGDefinePtr *tmp;
4132 int res;
Daniel Veillarde063f482003-03-21 16:53:17 +00004133
Daniel Veillard4c004142003-10-07 11:33:24 +00004134 tmp = list[i];
4135 while ((*tmp != NULL) && (is_triable == 1)) {
4136 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4137 res = xmlHashAddEntry2(triage,
4138 BAD_CAST "#text", NULL,
4139 (void *) cur);
4140 if (res != 0)
4141 is_triable = -1;
4142 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4143 ((*tmp)->name != NULL)) {
4144 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4145 res = xmlHashAddEntry2(triage,
4146 (*tmp)->name, NULL,
4147 (void *) cur);
4148 else
4149 res = xmlHashAddEntry2(triage,
4150 (*tmp)->name, (*tmp)->ns,
4151 (void *) cur);
4152 if (res != 0)
4153 is_triable = -1;
4154 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4155 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4156 res = xmlHashAddEntry2(triage,
4157 BAD_CAST "#any", NULL,
4158 (void *) cur);
4159 else
4160 res = xmlHashAddEntry2(triage,
4161 BAD_CAST "#any", (*tmp)->ns,
4162 (void *) cur);
4163 if (res != 0)
4164 is_triable = -1;
4165 } else {
4166 is_triable = -1;
4167 }
4168 tmp++;
4169 }
4170 }
4171 i++;
4172 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004173 }
4174
Daniel Veillard4c004142003-10-07 11:33:24 +00004175 for (i = 0; i < nbchild; i++) {
4176 if (list[i] == NULL)
4177 continue;
4178 for (j = 0; j < i; j++) {
4179 if (list[j] == NULL)
4180 continue;
4181 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4182 if (ret == 0) {
4183 is_indeterminist = 1;
4184 }
4185 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004186 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004187 for (i = 0; i < nbchild; i++) {
4188 if (list[i] != NULL)
4189 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004190 }
4191
4192 xmlFree(list);
4193 if (is_indeterminist) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004194 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004195 }
Daniel Veillarde063f482003-03-21 16:53:17 +00004196 if (is_triable == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004197 def->dflags |= IS_TRIABLE;
4198 def->data = triage;
Daniel Veillarde063f482003-03-21 16:53:17 +00004199 } else if (triage != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004200 xmlHashFree(triage, NULL);
Daniel Veillarde063f482003-03-21 16:53:17 +00004201 }
4202 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004203}
4204
4205/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004206 * xmlRelaxNGCheckGroupAttrs:
4207 * @ctxt: a Relax-NG parser context
4208 * @def: the group definition
4209 *
4210 * Detects violations of rule 7.3
4211 */
4212static void
4213xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004214 xmlRelaxNGDefinePtr def)
4215{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004216 xmlRelaxNGDefinePtr **list;
4217 xmlRelaxNGDefinePtr cur;
4218 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004219
4220 if ((def == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00004221 ((def->type != XML_RELAXNG_GROUP) &&
4222 (def->type != XML_RELAXNG_ELEMENT)))
4223 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004224
Daniel Veillarde063f482003-03-21 16:53:17 +00004225 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004226 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004227
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004228 /*
4229 * Don't run that check in case of error. Infinite recursion
4230 * becomes possible.
4231 */
4232 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004233 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004234
Daniel Veillardfd573f12003-03-16 17:52:32 +00004235 cur = def->attrs;
4236 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004237 nbchild++;
4238 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004239 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004240 cur = def->content;
4241 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004242 nbchild++;
4243 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004244 }
4245
4246 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004247 sizeof(xmlRelaxNGDefinePtr
4248 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004249 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004250 xmlRngPErrMemory(ctxt, "building group\n");
4251 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004252 }
4253 i = 0;
4254 cur = def->attrs;
4255 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004256 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4257 i++;
4258 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004259 }
4260 cur = def->content;
4261 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004262 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4263 i++;
4264 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004265 }
4266
Daniel Veillard4c004142003-10-07 11:33:24 +00004267 for (i = 0; i < nbchild; i++) {
4268 if (list[i] == NULL)
4269 continue;
4270 for (j = 0; j < i; j++) {
4271 if (list[j] == NULL)
4272 continue;
4273 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4274 if (ret == 0) {
4275 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4276 "Attributes conflicts in group\n", NULL, NULL);
4277 }
4278 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004279 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004280 for (i = 0; i < nbchild; i++) {
4281 if (list[i] != NULL)
4282 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004283 }
4284
4285 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00004286 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004287}
4288
4289/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004290 * xmlRelaxNGComputeInterleaves:
4291 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004292 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00004293 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004294 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00004295 * A lot of work for preprocessing interleave definitions
4296 * is potentially needed to get a decent execution speed at runtime
4297 * - trying to get a total order on the element nodes generated
4298 * by the interleaves, order the list of interleave definitions
4299 * following that order.
4300 * - if <text/> is used to handle mixed content, it is better to
4301 * flag this in the define and simplify the runtime checking
4302 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004303 */
4304static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00004305xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
Daniel Veillard4c004142003-10-07 11:33:24 +00004306 xmlRelaxNGParserCtxtPtr ctxt,
4307 xmlChar * name ATTRIBUTE_UNUSED)
4308{
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004309 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004310
Daniel Veillardfd573f12003-03-16 17:52:32 +00004311 xmlRelaxNGPartitionPtr partitions = NULL;
4312 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4313 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillard4c004142003-10-07 11:33:24 +00004314 int i, j, ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004315 int nbgroups = 0;
4316 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004317 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004318 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004319
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004320 /*
4321 * Don't run that check in case of error. Infinite recursion
4322 * becomes possible.
4323 */
4324 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004325 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004326
Daniel Veillardfd573f12003-03-16 17:52:32 +00004327#ifdef DEBUG_INTERLEAVE
4328 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00004329 "xmlRelaxNGComputeInterleaves(%s)\n", name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004330#endif
4331 cur = def->content;
4332 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004333 nbchild++;
4334 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004335 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004336
Daniel Veillardfd573f12003-03-16 17:52:32 +00004337#ifdef DEBUG_INTERLEAVE
4338 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
4339#endif
4340 groups = (xmlRelaxNGInterleaveGroupPtr *)
Daniel Veillard4c004142003-10-07 11:33:24 +00004341 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004342 if (groups == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004343 goto error;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004344 cur = def->content;
4345 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004346 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4347 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4348 if (groups[nbgroups] == NULL)
4349 goto error;
4350 if (cur->type == XML_RELAXNG_TEXT)
4351 is_mixed++;
4352 groups[nbgroups]->rule = cur;
4353 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4354 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4355 nbgroups++;
4356 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004357 }
4358#ifdef DEBUG_INTERLEAVE
4359 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4360#endif
4361
4362 /*
4363 * Let's check that all rules makes a partitions according to 7.4
4364 */
4365 partitions = (xmlRelaxNGPartitionPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00004366 xmlMalloc(sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004367 if (partitions == NULL)
4368 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004369 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004370 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004371 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillard4c004142003-10-07 11:33:24 +00004372 for (i = 0; i < nbgroups; i++) {
4373 group = groups[i];
4374 for (j = i + 1; j < nbgroups; j++) {
4375 if (groups[j] == NULL)
4376 continue;
4377
4378 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4379 groups[j]->defs);
4380 if (ret == 0) {
4381 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4382 "Element or text conflicts in interleave\n",
4383 NULL, NULL);
4384 }
4385 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4386 groups[j]->attrs);
4387 if (ret == 0) {
4388 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4389 "Attributes conflicts in interleave\n", NULL,
4390 NULL);
4391 }
4392 }
4393 tmp = group->defs;
4394 if ((tmp != NULL) && (*tmp != NULL)) {
4395 while (*tmp != NULL) {
4396 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4397 res = xmlHashAddEntry2(partitions->triage,
4398 BAD_CAST "#text", NULL,
4399 (void *) (long) (i + 1));
4400 if (res != 0)
4401 is_determinist = -1;
4402 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4403 ((*tmp)->name != NULL)) {
4404 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4405 res = xmlHashAddEntry2(partitions->triage,
4406 (*tmp)->name, NULL,
4407 (void *) (long) (i + 1));
4408 else
4409 res = xmlHashAddEntry2(partitions->triage,
4410 (*tmp)->name, (*tmp)->ns,
4411 (void *) (long) (i + 1));
4412 if (res != 0)
4413 is_determinist = -1;
4414 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4415 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4416 res = xmlHashAddEntry2(partitions->triage,
4417 BAD_CAST "#any", NULL,
4418 (void *) (long) (i + 1));
4419 else
4420 res = xmlHashAddEntry2(partitions->triage,
4421 BAD_CAST "#any", (*tmp)->ns,
4422 (void *) (long) (i + 1));
4423 if ((*tmp)->nameClass != NULL)
4424 is_determinist = 2;
4425 if (res != 0)
4426 is_determinist = -1;
4427 } else {
4428 is_determinist = -1;
4429 }
4430 tmp++;
4431 }
4432 } else {
4433 is_determinist = 0;
4434 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004435 }
4436 partitions->groups = groups;
4437
4438 /*
4439 * and save the partition list back in the def
4440 */
4441 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004442 if (is_mixed != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004443 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004444 if (is_determinist == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00004445 partitions->flags = IS_DETERMINIST;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004446 if (is_determinist == 2)
Daniel Veillard4c004142003-10-07 11:33:24 +00004447 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004448 return;
4449
Daniel Veillard4c004142003-10-07 11:33:24 +00004450 error:
4451 xmlRngPErrMemory(ctxt, "in interleave computation\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004452 if (groups != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004453 for (i = 0; i < nbgroups; i++)
4454 if (groups[i] != NULL) {
4455 if (groups[i]->defs != NULL)
4456 xmlFree(groups[i]->defs);
4457 xmlFree(groups[i]);
4458 }
4459 xmlFree(groups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004460 }
4461 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004462}
4463
4464/**
4465 * xmlRelaxNGParseInterleave:
4466 * @ctxt: a Relax-NG parser context
4467 * @node: the data node.
4468 *
4469 * parse the content of a RelaxNG interleave node.
4470 *
4471 * Returns the definition pointer or NULL in case of error
4472 */
4473static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004474xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4475{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004476 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004477 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004478 xmlNodePtr child;
4479
Daniel Veillardfd573f12003-03-16 17:52:32 +00004480 def = xmlRelaxNGNewDefine(ctxt, node);
4481 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004482 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004483 }
4484 def->type = XML_RELAXNG_INTERLEAVE;
4485
4486 if (ctxt->interleaves == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004487 ctxt->interleaves = xmlHashCreate(10);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004488 if (ctxt->interleaves == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004489 xmlRngPErrMemory(ctxt, "create interleaves\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004490 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004491 char name[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00004492
Daniel Veillard4c004142003-10-07 11:33:24 +00004493 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4494 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4495 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4496 "Failed to add %s to hash table\n",
4497 (const xmlChar *) name, NULL);
4498 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004499 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004500 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004501 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004502 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4503 "Element interleave is empty\n", NULL, NULL);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004504 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004505 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004506 if (IS_RELAXNG(child, "element")) {
4507 cur = xmlRelaxNGParseElement(ctxt, child);
4508 } else {
4509 cur = xmlRelaxNGParsePattern(ctxt, child);
4510 }
4511 if (cur != NULL) {
4512 cur->parent = def;
4513 if (last == NULL) {
4514 def->content = last = cur;
4515 } else {
4516 last->next = cur;
4517 last = cur;
4518 }
4519 }
4520 child = child->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004521 }
4522
Daniel Veillard4c004142003-10-07 11:33:24 +00004523 return (def);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004524}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004525
4526/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004527 * xmlRelaxNGParseInclude:
4528 * @ctxt: a Relax-NG parser context
4529 * @node: the include node
4530 *
4531 * Integrate the content of an include node in the current grammar
4532 *
4533 * Returns 0 in case of success or -1 in case of error
4534 */
4535static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004536xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4537{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004538 xmlRelaxNGIncludePtr incl;
4539 xmlNodePtr root;
4540 int ret = 0, tmp;
4541
Daniel Veillard807daf82004-02-22 22:13:27 +00004542 incl = node->psvi;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004543 if (incl == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004544 xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4545 "Include node has no data\n", NULL, NULL);
4546 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004547 }
4548 root = xmlDocGetRootElement(incl->doc);
4549 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004550 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4551 NULL, NULL);
4552 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004553 }
4554 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004555 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4556 "Include document root is not a grammar\n", NULL, NULL);
4557 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004558 }
4559
4560 /*
4561 * Merge the definition from both the include and the internal list
4562 */
4563 if (root->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004564 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4565 if (tmp != 0)
4566 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004567 }
4568 if (node->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004569 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4570 if (tmp != 0)
4571 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004572 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004573 return (ret);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004574}
4575
4576/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004577 * xmlRelaxNGParseDefine:
4578 * @ctxt: a Relax-NG parser context
4579 * @node: the define node
4580 *
4581 * parse the content of a RelaxNG define element node.
4582 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004583 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004584 */
4585static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004586xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4587{
Daniel Veillard276be4a2003-01-24 01:03:34 +00004588 xmlChar *name;
4589 int ret = 0, tmp;
4590 xmlRelaxNGDefinePtr def;
4591 const xmlChar *olddefine;
4592
4593 name = xmlGetProp(node, BAD_CAST "name");
4594 if (name == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004595 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4596 "define has no name\n", NULL, NULL);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004597 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004598 xmlRelaxNGNormExtSpace(name);
4599 if (xmlValidateNCName(name, 0)) {
4600 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4601 "define name '%s' is not an NCName\n", name, NULL);
4602 }
4603 def = xmlRelaxNGNewDefine(ctxt, node);
4604 if (def == NULL) {
4605 xmlFree(name);
4606 return (-1);
4607 }
4608 def->type = XML_RELAXNG_DEF;
4609 def->name = name;
4610 if (node->children == NULL) {
4611 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4612 "define has no children\n", NULL, NULL);
4613 } else {
4614 olddefine = ctxt->define;
4615 ctxt->define = name;
4616 def->content =
4617 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4618 ctxt->define = olddefine;
4619 }
4620 if (ctxt->grammar->defs == NULL)
4621 ctxt->grammar->defs = xmlHashCreate(10);
4622 if (ctxt->grammar->defs == NULL) {
4623 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4624 "Could not create definition hash\n", NULL, NULL);
4625 ret = -1;
4626 } else {
4627 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4628 if (tmp < 0) {
4629 xmlRelaxNGDefinePtr prev;
Daniel Veillard154877e2003-01-30 12:17:05 +00004630
Daniel Veillard4c004142003-10-07 11:33:24 +00004631 prev = xmlHashLookup(ctxt->grammar->defs, name);
4632 if (prev == NULL) {
4633 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4634 "Internal error on define aggregation of %s\n",
4635 name, NULL);
4636 ret = -1;
4637 } else {
4638 while (prev->nextHash != NULL)
4639 prev = prev->nextHash;
4640 prev->nextHash = def;
4641 }
4642 }
4643 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004644 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004645 return (ret);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004646}
4647
4648/**
Daniel Veillard81c51e12009-08-14 18:52:10 +02004649 * xmlRelaxNGParseImportRef:
4650 * @payload: the parser context
4651 * @data: the current grammar
4652 * @name: the reference name
4653 *
4654 * Import import one references into the current grammar
4655 */
4656static void
4657xmlRelaxNGParseImportRef(void *payload, void *data, xmlChar *name) {
4658 xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
4659 xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
4660 int tmp;
4661
4662 tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def);
4663 if (tmp < 0) {
4664 xmlRelaxNGDefinePtr prev;
4665
4666 prev = (xmlRelaxNGDefinePtr)
4667 xmlHashLookup(ctxt->grammar->refs, def->name);
4668 if (prev == NULL) {
4669 if (def->name != NULL) {
4670 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4671 "Error refs definitions '%s'\n",
4672 def->name, NULL);
4673 } else {
4674 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4675 "Error refs definitions\n",
4676 NULL, NULL);
4677 }
4678 } else {
4679 def->nextHash = prev->nextHash;
4680 prev->nextHash = def;
4681 }
4682 }
4683}
4684
4685/**
4686 * xmlRelaxNGParseImportRefs:
4687 * @ctxt: the parser context
4688 * @grammar: the sub grammar
4689 *
4690 * Import references from the subgrammar into the current grammar
4691 *
4692 * Returns 0 in case of success, -1 in case of failure
4693 */
4694static int
4695xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt,
4696 xmlRelaxNGGrammarPtr grammar) {
4697 if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL))
4698 return(-1);
4699 if (grammar->refs == NULL)
4700 return(0);
4701 if (ctxt->grammar->refs == NULL)
4702 ctxt->grammar->refs = xmlHashCreate(10);
4703 if (ctxt->grammar->refs == NULL) {
4704 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4705 "Could not create references hash\n", NULL, NULL);
4706 return(-1);
4707 }
4708 xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt);
Daniel Veillardec18c962009-08-26 18:37:43 +02004709 return(0);
Daniel Veillard81c51e12009-08-14 18:52:10 +02004710}
4711
4712/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004713 * xmlRelaxNGProcessExternalRef:
4714 * @ctxt: the parser context
4715 * @node: the externlRef node
4716 *
4717 * Process and compile an externlRef node
4718 *
4719 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4720 */
4721static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004722xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4723{
Daniel Veillardfebcca42003-02-16 15:44:18 +00004724 xmlRelaxNGDocumentPtr docu;
4725 xmlNodePtr root, tmp;
4726 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004727 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004728 xmlRelaxNGDefinePtr def;
4729
Daniel Veillard807daf82004-02-22 22:13:27 +00004730 docu = node->psvi;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004731 if (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004732 def = xmlRelaxNGNewDefine(ctxt, node);
4733 if (def == NULL)
4734 return (NULL);
4735 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004736
Daniel Veillard4c004142003-10-07 11:33:24 +00004737 if (docu->content == NULL) {
4738 /*
4739 * Then do the parsing for good
4740 */
4741 root = xmlDocGetRootElement(docu->doc);
4742 if (root == NULL) {
4743 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
4744 "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
4745 NULL);
4746 return (NULL);
4747 }
4748 /*
4749 * ns transmission rules
4750 */
4751 ns = xmlGetProp(root, BAD_CAST "ns");
4752 if (ns == NULL) {
4753 tmp = node;
4754 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
4755 ns = xmlGetProp(tmp, BAD_CAST "ns");
4756 if (ns != NULL) {
4757 break;
4758 }
4759 tmp = tmp->parent;
4760 }
4761 if (ns != NULL) {
4762 xmlSetProp(root, BAD_CAST "ns", ns);
4763 newNs = 1;
4764 xmlFree(ns);
4765 }
4766 } else {
4767 xmlFree(ns);
4768 }
Daniel Veillardfebcca42003-02-16 15:44:18 +00004769
Daniel Veillard4c004142003-10-07 11:33:24 +00004770 /*
4771 * Parsing to get a precompiled schemas.
4772 */
4773 oldflags = ctxt->flags;
4774 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4775 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4776 ctxt->flags = oldflags;
4777 if ((docu->schema != NULL) &&
4778 (docu->schema->topgrammar != NULL)) {
4779 docu->content = docu->schema->topgrammar->start;
Daniel Veillard81c51e12009-08-14 18:52:10 +02004780 if (docu->schema->topgrammar->refs)
4781 xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar);
Daniel Veillard4c004142003-10-07 11:33:24 +00004782 }
4783
4784 /*
4785 * the externalRef may be reused in a different ns context
4786 */
4787 if (newNs == 1) {
4788 xmlUnsetProp(root, BAD_CAST "ns");
4789 }
4790 }
4791 def->content = docu->content;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004792 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004793 def = NULL;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004794 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004795 return (def);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004796}
4797
4798/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004799 * xmlRelaxNGParsePattern:
4800 * @ctxt: a Relax-NG parser context
4801 * @node: the pattern node.
4802 *
4803 * parse the content of a RelaxNG pattern node.
4804 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004805 * Returns the definition pointer or NULL in case of error or if no
4806 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004807 */
4808static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004809xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4810{
Daniel Veillard6eadf632003-01-23 18:29:16 +00004811 xmlRelaxNGDefinePtr def = NULL;
4812
Daniel Veillardd2298792003-02-14 16:54:11 +00004813 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004814 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004815 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004816 if (IS_RELAXNG(node, "element")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004817 def = xmlRelaxNGParseElement(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004818 } else if (IS_RELAXNG(node, "attribute")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004819 def = xmlRelaxNGParseAttribute(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004820 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004821 def = xmlRelaxNGNewDefine(ctxt, node);
4822 if (def == NULL)
4823 return (NULL);
4824 def->type = XML_RELAXNG_EMPTY;
4825 if (node->children != NULL) {
4826 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
4827 "empty: had a child node\n", NULL, NULL);
4828 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004829 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004830 def = xmlRelaxNGNewDefine(ctxt, node);
4831 if (def == NULL)
4832 return (NULL);
4833 def->type = XML_RELAXNG_TEXT;
4834 if (node->children != NULL) {
4835 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
4836 "text: had a child node\n", NULL, NULL);
4837 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004838 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004839 def = xmlRelaxNGNewDefine(ctxt, node);
4840 if (def == NULL)
4841 return (NULL);
4842 def->type = XML_RELAXNG_ZEROORMORE;
4843 if (node->children == NULL) {
4844 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4845 "Element %s is empty\n", node->name, NULL);
4846 } else {
4847 def->content =
4848 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4849 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004850 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004851 def = xmlRelaxNGNewDefine(ctxt, node);
4852 if (def == NULL)
4853 return (NULL);
4854 def->type = XML_RELAXNG_ONEORMORE;
4855 if (node->children == NULL) {
4856 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4857 "Element %s is empty\n", node->name, NULL);
4858 } else {
4859 def->content =
4860 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4861 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004862 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004863 def = xmlRelaxNGNewDefine(ctxt, node);
4864 if (def == NULL)
4865 return (NULL);
4866 def->type = XML_RELAXNG_OPTIONAL;
4867 if (node->children == NULL) {
4868 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4869 "Element %s is empty\n", node->name, NULL);
4870 } else {
4871 def->content =
4872 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4873 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004874 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004875 def = xmlRelaxNGNewDefine(ctxt, node);
4876 if (def == NULL)
4877 return (NULL);
4878 def->type = XML_RELAXNG_CHOICE;
4879 if (node->children == NULL) {
4880 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4881 "Element %s is empty\n", node->name, NULL);
4882 } else {
4883 def->content =
4884 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4885 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004886 } else if (IS_RELAXNG(node, "group")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004887 def = xmlRelaxNGNewDefine(ctxt, node);
4888 if (def == NULL)
4889 return (NULL);
4890 def->type = XML_RELAXNG_GROUP;
4891 if (node->children == NULL) {
4892 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4893 "Element %s is empty\n", node->name, NULL);
4894 } else {
4895 def->content =
4896 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4897 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004898 } else if (IS_RELAXNG(node, "ref")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004899 def = xmlRelaxNGNewDefine(ctxt, node);
4900 if (def == NULL)
4901 return (NULL);
4902 def->type = XML_RELAXNG_REF;
4903 def->name = xmlGetProp(node, BAD_CAST "name");
4904 if (def->name == NULL) {
4905 xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
4906 NULL, NULL);
4907 } else {
4908 xmlRelaxNGNormExtSpace(def->name);
4909 if (xmlValidateNCName(def->name, 0)) {
4910 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
4911 "ref name '%s' is not an NCName\n", def->name,
4912 NULL);
4913 }
4914 }
4915 if (node->children != NULL) {
4916 xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
4917 NULL, NULL);
4918 }
4919 if (ctxt->grammar->refs == NULL)
4920 ctxt->grammar->refs = xmlHashCreate(10);
4921 if (ctxt->grammar->refs == NULL) {
4922 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4923 "Could not create references hash\n", NULL, NULL);
4924 def = NULL;
4925 } else {
4926 int tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004927
Daniel Veillard4c004142003-10-07 11:33:24 +00004928 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4929 if (tmp < 0) {
4930 xmlRelaxNGDefinePtr prev;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004931
Daniel Veillard4c004142003-10-07 11:33:24 +00004932 prev = (xmlRelaxNGDefinePtr)
4933 xmlHashLookup(ctxt->grammar->refs, def->name);
4934 if (prev == NULL) {
4935 if (def->name != NULL) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004936 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4937 "Error refs definitions '%s'\n",
4938 def->name, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004939 } else {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004940 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4941 "Error refs definitions\n",
4942 NULL, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004943 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004944 def = NULL;
4945 } else {
4946 def->nextHash = prev->nextHash;
4947 prev->nextHash = def;
4948 }
4949 }
4950 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004951 } else if (IS_RELAXNG(node, "data")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004952 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004953 } else if (IS_RELAXNG(node, "value")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004954 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004955 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004956 def = xmlRelaxNGNewDefine(ctxt, node);
4957 if (def == NULL)
4958 return (NULL);
4959 def->type = XML_RELAXNG_LIST;
4960 if (node->children == NULL) {
4961 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4962 "Element %s is empty\n", node->name, NULL);
4963 } else {
4964 def->content =
4965 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4966 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004967 } else if (IS_RELAXNG(node, "interleave")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004968 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004969 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004970 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004971 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004972 def = xmlRelaxNGNewDefine(ctxt, node);
4973 if (def == NULL)
4974 return (NULL);
4975 def->type = XML_RELAXNG_NOT_ALLOWED;
4976 if (node->children != NULL) {
4977 xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
4978 "xmlRelaxNGParse: notAllowed element is not empty\n",
4979 NULL, NULL);
4980 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004981 } else if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004982 xmlRelaxNGGrammarPtr grammar, old;
4983 xmlRelaxNGGrammarPtr oldparent;
Daniel Veillard419a7682003-02-03 23:22:49 +00004984
Daniel Veillardc482e262003-02-26 14:48:48 +00004985#ifdef DEBUG_GRAMMAR
Daniel Veillard4c004142003-10-07 11:33:24 +00004986 xmlGenericError(xmlGenericErrorContext,
4987 "Found <grammar> pattern\n");
Daniel Veillardc482e262003-02-26 14:48:48 +00004988#endif
4989
Daniel Veillard4c004142003-10-07 11:33:24 +00004990 oldparent = ctxt->parentgrammar;
4991 old = ctxt->grammar;
4992 ctxt->parentgrammar = old;
4993 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4994 if (old != NULL) {
4995 ctxt->grammar = old;
4996 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004997#if 0
Daniel Veillard4c004142003-10-07 11:33:24 +00004998 if (grammar != NULL) {
4999 grammar->next = old->next;
5000 old->next = grammar;
5001 }
Daniel Veillardc482e262003-02-26 14:48:48 +00005002#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00005003 }
5004 if (grammar != NULL)
5005 def = grammar->start;
5006 else
5007 def = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00005008 } else if (IS_RELAXNG(node, "parentRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005009 if (ctxt->parentgrammar == NULL) {
5010 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
5011 "Use of parentRef without a parent grammar\n", NULL,
5012 NULL);
5013 return (NULL);
5014 }
5015 def = xmlRelaxNGNewDefine(ctxt, node);
5016 if (def == NULL)
5017 return (NULL);
5018 def->type = XML_RELAXNG_PARENTREF;
5019 def->name = xmlGetProp(node, BAD_CAST "name");
5020 if (def->name == NULL) {
5021 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
5022 "parentRef has no name\n", NULL, NULL);
5023 } else {
5024 xmlRelaxNGNormExtSpace(def->name);
5025 if (xmlValidateNCName(def->name, 0)) {
5026 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
5027 "parentRef name '%s' is not an NCName\n",
5028 def->name, NULL);
5029 }
5030 }
5031 if (node->children != NULL) {
5032 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
5033 "parentRef is not empty\n", NULL, NULL);
5034 }
5035 if (ctxt->parentgrammar->refs == NULL)
5036 ctxt->parentgrammar->refs = xmlHashCreate(10);
5037 if (ctxt->parentgrammar->refs == NULL) {
5038 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
5039 "Could not create references hash\n", NULL, NULL);
5040 def = NULL;
5041 } else if (def->name != NULL) {
5042 int tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +00005043
Daniel Veillard4c004142003-10-07 11:33:24 +00005044 tmp =
5045 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
5046 if (tmp < 0) {
5047 xmlRelaxNGDefinePtr prev;
Daniel Veillard419a7682003-02-03 23:22:49 +00005048
Daniel Veillard4c004142003-10-07 11:33:24 +00005049 prev = (xmlRelaxNGDefinePtr)
5050 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
5051 if (prev == NULL) {
5052 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
5053 "Internal error parentRef definitions '%s'\n",
5054 def->name, NULL);
5055 def = NULL;
5056 } else {
5057 def->nextHash = prev->nextHash;
5058 prev->nextHash = def;
5059 }
5060 }
5061 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005062 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005063 if (node->children == NULL) {
5064 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
5065 NULL, NULL);
5066 def = NULL;
5067 } else {
5068 def = xmlRelaxNGParseInterleave(ctxt, node);
5069 if (def != NULL) {
5070 xmlRelaxNGDefinePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005071
Daniel Veillard4c004142003-10-07 11:33:24 +00005072 if ((def->content != NULL) && (def->content->next != NULL)) {
5073 tmp = xmlRelaxNGNewDefine(ctxt, node);
5074 if (tmp != NULL) {
5075 tmp->type = XML_RELAXNG_GROUP;
5076 tmp->content = def->content;
5077 def->content = tmp;
5078 }
5079 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005080
Daniel Veillard4c004142003-10-07 11:33:24 +00005081 tmp = xmlRelaxNGNewDefine(ctxt, node);
5082 if (tmp == NULL)
5083 return (def);
5084 tmp->type = XML_RELAXNG_TEXT;
5085 tmp->next = def->content;
5086 def->content = tmp;
5087 }
5088 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005089 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005090 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
5091 "Unexpected node %s is not a pattern\n", node->name,
5092 NULL);
5093 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005094 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005095 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005096}
5097
5098/**
5099 * xmlRelaxNGParseAttribute:
5100 * @ctxt: a Relax-NG parser context
5101 * @node: the element node
5102 *
5103 * parse the content of a RelaxNG attribute node.
5104 *
5105 * Returns the definition pointer or NULL in case of error.
5106 */
5107static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005108xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5109{
Daniel Veillardd2298792003-02-14 16:54:11 +00005110 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005111 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005112 int old_flags;
5113
Daniel Veillardfd573f12003-03-16 17:52:32 +00005114 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005115 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005116 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005117 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005118 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005119 child = node->children;
5120 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005121 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
5122 "xmlRelaxNGParseattribute: attribute has no children\n",
5123 NULL, NULL);
5124 return (ret);
5125 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005126 old_flags = ctxt->flags;
5127 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005128 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5129 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005130 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005131
Daniel Veillardd2298792003-02-14 16:54:11 +00005132 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005133 cur = xmlRelaxNGParsePattern(ctxt, child);
5134 if (cur != NULL) {
5135 switch (cur->type) {
5136 case XML_RELAXNG_EMPTY:
5137 case XML_RELAXNG_NOT_ALLOWED:
5138 case XML_RELAXNG_TEXT:
5139 case XML_RELAXNG_ELEMENT:
5140 case XML_RELAXNG_DATATYPE:
5141 case XML_RELAXNG_VALUE:
5142 case XML_RELAXNG_LIST:
5143 case XML_RELAXNG_REF:
5144 case XML_RELAXNG_PARENTREF:
5145 case XML_RELAXNG_EXTERNALREF:
5146 case XML_RELAXNG_DEF:
5147 case XML_RELAXNG_ONEORMORE:
5148 case XML_RELAXNG_ZEROORMORE:
5149 case XML_RELAXNG_OPTIONAL:
5150 case XML_RELAXNG_CHOICE:
5151 case XML_RELAXNG_GROUP:
5152 case XML_RELAXNG_INTERLEAVE:
5153 case XML_RELAXNG_ATTRIBUTE:
5154 ret->content = cur;
5155 cur->parent = ret;
5156 break;
5157 case XML_RELAXNG_START:
5158 case XML_RELAXNG_PARAM:
5159 case XML_RELAXNG_EXCEPT:
5160 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
5161 "attribute has invalid content\n", NULL,
5162 NULL);
5163 break;
5164 case XML_RELAXNG_NOOP:
5165 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
5166 "RNG Internal error, noop found in attribute\n",
5167 NULL, NULL);
5168 break;
5169 }
5170 }
5171 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005172 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005173 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005174 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
5175 "attribute has multiple children\n", NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005176 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005177 ctxt->flags = old_flags;
Daniel Veillard4c004142003-10-07 11:33:24 +00005178 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005179}
5180
5181/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005182 * xmlRelaxNGParseExceptNameClass:
5183 * @ctxt: a Relax-NG parser context
5184 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00005185 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005186 *
5187 * parse the content of a RelaxNG nameClass node.
5188 *
5189 * Returns the definition pointer or NULL in case of error.
5190 */
5191static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00005192xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005193 xmlNodePtr node, int attr)
5194{
Daniel Veillard144fae12003-02-03 13:17:57 +00005195 xmlRelaxNGDefinePtr ret, cur, last = NULL;
5196 xmlNodePtr child;
5197
Daniel Veillardd2298792003-02-14 16:54:11 +00005198 if (!IS_RELAXNG(node, "except")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005199 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
5200 "Expecting an except node\n", NULL, NULL);
5201 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005202 }
5203 if (node->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005204 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
5205 "exceptNameClass allows only a single except node\n",
5206 NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005207 }
Daniel Veillard144fae12003-02-03 13:17:57 +00005208 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005209 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
5210 NULL, NULL);
5211 return (NULL);
Daniel Veillard144fae12003-02-03 13:17:57 +00005212 }
5213
Daniel Veillardfd573f12003-03-16 17:52:32 +00005214 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00005215 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005216 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005217 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00005218 child = node->children;
5219 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005220 cur = xmlRelaxNGNewDefine(ctxt, child);
5221 if (cur == NULL)
5222 break;
5223 if (attr)
5224 cur->type = XML_RELAXNG_ATTRIBUTE;
5225 else
5226 cur->type = XML_RELAXNG_ELEMENT;
5227
Daniel Veillard419a7682003-02-03 23:22:49 +00005228 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005229 if (last == NULL) {
5230 ret->content = cur;
5231 } else {
5232 last->next = cur;
5233 }
5234 last = cur;
5235 }
5236 child = child->next;
Daniel Veillard144fae12003-02-03 13:17:57 +00005237 }
5238
Daniel Veillard4c004142003-10-07 11:33:24 +00005239 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005240}
5241
5242/**
5243 * xmlRelaxNGParseNameClass:
5244 * @ctxt: a Relax-NG parser context
5245 * @node: the nameClass node
5246 * @def: the current definition
5247 *
5248 * parse the content of a RelaxNG nameClass node.
5249 *
5250 * Returns the definition pointer or NULL in case of error.
5251 */
5252static xmlRelaxNGDefinePtr
5253xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillard4c004142003-10-07 11:33:24 +00005254 xmlRelaxNGDefinePtr def)
5255{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005256 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005257 xmlChar *val;
5258
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005259 ret = def;
Daniel Veillard4c004142003-10-07 11:33:24 +00005260 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005261 (IS_RELAXNG(node, "nsName"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005262 if ((def->type != XML_RELAXNG_ELEMENT) &&
5263 (def->type != XML_RELAXNG_ATTRIBUTE)) {
5264 ret = xmlRelaxNGNewDefine(ctxt, node);
5265 if (ret == NULL)
5266 return (NULL);
5267 ret->parent = def;
5268 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5269 ret->type = XML_RELAXNG_ATTRIBUTE;
5270 else
5271 ret->type = XML_RELAXNG_ELEMENT;
5272 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005273 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005274 if (IS_RELAXNG(node, "name")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005275 val = xmlNodeGetContent(node);
5276 xmlRelaxNGNormExtSpace(val);
5277 if (xmlValidateNCName(val, 0)) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005278 if (node->parent != NULL)
5279 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5280 "Element %s name '%s' is not an NCName\n",
5281 node->parent->name, val);
5282 else
5283 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5284 "name '%s' is not an NCName\n",
5285 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005286 }
5287 ret->name = val;
5288 val = xmlGetProp(node, BAD_CAST "ns");
5289 ret->ns = val;
5290 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5291 (val != NULL) &&
5292 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005293 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
Daniel Veillard4c004142003-10-07 11:33:24 +00005294 "Attribute with namespace '%s' is not allowed\n",
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005295 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005296 }
5297 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5298 (val != NULL) &&
5299 (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005300 xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
5301 "Attribute with QName 'xmlns' is not allowed\n",
5302 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005303 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005304 } else if (IS_RELAXNG(node, "anyName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005305 ret->name = NULL;
5306 ret->ns = NULL;
5307 if (node->children != NULL) {
5308 ret->nameClass =
5309 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5310 (def->type ==
5311 XML_RELAXNG_ATTRIBUTE));
5312 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005313 } else if (IS_RELAXNG(node, "nsName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005314 ret->name = NULL;
5315 ret->ns = xmlGetProp(node, BAD_CAST "ns");
5316 if (ret->ns == NULL) {
5317 xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
5318 "nsName has no ns attribute\n", NULL, NULL);
5319 }
5320 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5321 (ret->ns != NULL) &&
5322 (xmlStrEqual
5323 (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5324 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5325 "Attribute with namespace '%s' is not allowed\n",
5326 ret->ns, NULL);
5327 }
5328 if (node->children != NULL) {
5329 ret->nameClass =
5330 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5331 (def->type ==
5332 XML_RELAXNG_ATTRIBUTE));
5333 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005334 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005335 xmlNodePtr child;
5336 xmlRelaxNGDefinePtr last = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005337
Daniel Veillard4c004142003-10-07 11:33:24 +00005338 ret = xmlRelaxNGNewDefine(ctxt, node);
5339 if (ret == NULL)
5340 return (NULL);
5341 ret->parent = def;
5342 ret->type = XML_RELAXNG_CHOICE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005343
Daniel Veillard4c004142003-10-07 11:33:24 +00005344 if (node->children == NULL) {
5345 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
5346 "Element choice is empty\n", NULL, NULL);
5347 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005348
Daniel Veillard4c004142003-10-07 11:33:24 +00005349 child = node->children;
5350 while (child != NULL) {
5351 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5352 if (tmp != NULL) {
5353 if (last == NULL) {
5354 last = ret->nameClass = tmp;
5355 } else {
5356 last->next = tmp;
5357 last = tmp;
5358 }
5359 }
5360 child = child->next;
5361 }
5362 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005363 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005364 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
5365 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard76d36452009-09-07 11:19:33 +02005366 (node == NULL ? 'nothing' : node->name), NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005367 return (NULL);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005368 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005369 if (ret != def) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005370 if (def->nameClass == NULL) {
5371 def->nameClass = ret;
5372 } else {
5373 tmp = def->nameClass;
5374 while (tmp->next != NULL) {
5375 tmp = tmp->next;
5376 }
5377 tmp->next = ret;
5378 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005379 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005380 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005381}
5382
5383/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005384 * xmlRelaxNGParseElement:
5385 * @ctxt: a Relax-NG parser context
5386 * @node: the element node
5387 *
5388 * parse the content of a RelaxNG element node.
5389 *
5390 * Returns the definition pointer or NULL in case of error.
5391 */
5392static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005393xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5394{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005395 xmlRelaxNGDefinePtr ret, cur, last;
5396 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005397 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005398
Daniel Veillardfd573f12003-03-16 17:52:32 +00005399 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005400 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005401 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005402 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005403 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005404 child = node->children;
5405 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005406 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
5407 "xmlRelaxNGParseElement: element has no children\n",
5408 NULL, NULL);
5409 return (ret);
5410 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005411 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5412 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005413 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005414
Daniel Veillard6eadf632003-01-23 18:29:16 +00005415 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005416 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
5417 "xmlRelaxNGParseElement: element has no content\n",
5418 NULL, NULL);
5419 return (ret);
5420 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005421 olddefine = ctxt->define;
5422 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005423 last = NULL;
5424 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005425 cur = xmlRelaxNGParsePattern(ctxt, child);
5426 if (cur != NULL) {
5427 cur->parent = ret;
5428 switch (cur->type) {
5429 case XML_RELAXNG_EMPTY:
5430 case XML_RELAXNG_NOT_ALLOWED:
5431 case XML_RELAXNG_TEXT:
5432 case XML_RELAXNG_ELEMENT:
5433 case XML_RELAXNG_DATATYPE:
5434 case XML_RELAXNG_VALUE:
5435 case XML_RELAXNG_LIST:
5436 case XML_RELAXNG_REF:
5437 case XML_RELAXNG_PARENTREF:
5438 case XML_RELAXNG_EXTERNALREF:
5439 case XML_RELAXNG_DEF:
5440 case XML_RELAXNG_ZEROORMORE:
5441 case XML_RELAXNG_ONEORMORE:
5442 case XML_RELAXNG_OPTIONAL:
5443 case XML_RELAXNG_CHOICE:
5444 case XML_RELAXNG_GROUP:
5445 case XML_RELAXNG_INTERLEAVE:
5446 if (last == NULL) {
5447 ret->content = last = cur;
5448 } else {
5449 if ((last->type == XML_RELAXNG_ELEMENT) &&
5450 (ret->content == last)) {
5451 ret->content = xmlRelaxNGNewDefine(ctxt, node);
5452 if (ret->content != NULL) {
5453 ret->content->type = XML_RELAXNG_GROUP;
5454 ret->content->content = last;
5455 } else {
5456 ret->content = last;
5457 }
5458 }
5459 last->next = cur;
5460 last = cur;
5461 }
5462 break;
5463 case XML_RELAXNG_ATTRIBUTE:
5464 cur->next = ret->attrs;
5465 ret->attrs = cur;
5466 break;
5467 case XML_RELAXNG_START:
5468 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5469 "RNG Internal error, start found in element\n",
5470 NULL, NULL);
5471 break;
5472 case XML_RELAXNG_PARAM:
5473 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5474 "RNG Internal error, param found in element\n",
5475 NULL, NULL);
5476 break;
5477 case XML_RELAXNG_EXCEPT:
5478 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5479 "RNG Internal error, except found in element\n",
5480 NULL, NULL);
5481 break;
5482 case XML_RELAXNG_NOOP:
5483 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5484 "RNG Internal error, noop found in element\n",
5485 NULL, NULL);
5486 break;
5487 }
5488 }
5489 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005490 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005491 ctxt->define = olddefine;
Daniel Veillard4c004142003-10-07 11:33:24 +00005492 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005493}
5494
5495/**
5496 * xmlRelaxNGParsePatterns:
5497 * @ctxt: a Relax-NG parser context
5498 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005499 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005500 *
5501 * parse the content of a RelaxNG start node.
5502 *
5503 * Returns the definition pointer or NULL in case of error.
5504 */
5505static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005506xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
Daniel Veillard4c004142003-10-07 11:33:24 +00005507 int group)
5508{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005509 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005510
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005511 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005512 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005513 if (IS_RELAXNG(nodes, "element")) {
5514 cur = xmlRelaxNGParseElement(ctxt, nodes);
5515 if (def == NULL) {
5516 def = last = cur;
5517 } else {
5518 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5519 (def == last)) {
5520 def = xmlRelaxNGNewDefine(ctxt, nodes);
5521 def->type = XML_RELAXNG_GROUP;
5522 def->content = last;
5523 }
5524 last->next = cur;
5525 last = cur;
5526 }
5527 cur->parent = parent;
5528 } else {
5529 cur = xmlRelaxNGParsePattern(ctxt, nodes);
5530 if (cur != NULL) {
5531 if (def == NULL) {
5532 def = last = cur;
5533 } else {
5534 last->next = cur;
5535 last = cur;
5536 }
5537 }
5538 }
5539 nodes = nodes->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005540 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005541 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005542}
5543
5544/**
5545 * xmlRelaxNGParseStart:
5546 * @ctxt: a Relax-NG parser context
5547 * @nodes: start children nodes
5548 *
5549 * parse the content of a RelaxNG start node.
5550 *
5551 * Returns 0 in case of success, -1 in case of error
5552 */
5553static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005554xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5555{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005556 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005557 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005558
Daniel Veillardd2298792003-02-14 16:54:11 +00005559 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005560 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
5561 NULL, NULL);
5562 return (-1);
Daniel Veillardd2298792003-02-14 16:54:11 +00005563 }
5564 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005565 def = xmlRelaxNGNewDefine(ctxt, nodes);
5566 if (def == NULL)
5567 return (-1);
5568 def->type = XML_RELAXNG_EMPTY;
5569 if (nodes->children != NULL) {
5570 xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
5571 "element empty is not empty\n", NULL, NULL);
5572 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005573 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005574 def = xmlRelaxNGNewDefine(ctxt, nodes);
5575 if (def == NULL)
5576 return (-1);
5577 def->type = XML_RELAXNG_NOT_ALLOWED;
5578 if (nodes->children != NULL) {
5579 xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5580 "element notAllowed is not empty\n", NULL, NULL);
5581 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005582 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005583 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005584 }
5585 if (ctxt->grammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005586 last = ctxt->grammar->start;
5587 while (last->next != NULL)
5588 last = last->next;
5589 last->next = def;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005590 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005591 ctxt->grammar->start = def;
Daniel Veillardd2298792003-02-14 16:54:11 +00005592 }
5593 nodes = nodes->next;
5594 if (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005595 xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
5596 "start more than one children\n", NULL, NULL);
5597 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005598 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005599 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005600}
5601
5602/**
5603 * xmlRelaxNGParseGrammarContent:
5604 * @ctxt: a Relax-NG parser context
5605 * @nodes: grammar children nodes
5606 *
5607 * parse the content of a RelaxNG grammar node.
5608 *
5609 * Returns 0 in case of success, -1 in case of error
5610 */
5611static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005612xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
5613 xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005614{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005615 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005616
5617 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005618 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
5619 "grammar has no children\n", NULL, NULL);
5620 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005621 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005622 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005623 if (IS_RELAXNG(nodes, "start")) {
5624 if (nodes->children == NULL) {
5625 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
5626 "start has no children\n", NULL, NULL);
5627 } else {
5628 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5629 if (tmp != 0)
5630 ret = -1;
5631 }
5632 } else if (IS_RELAXNG(nodes, "define")) {
5633 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5634 if (tmp != 0)
5635 ret = -1;
5636 } else if (IS_RELAXNG(nodes, "include")) {
5637 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5638 if (tmp != 0)
5639 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005640 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005641 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
5642 "grammar has unexpected child %s\n", nodes->name,
5643 NULL);
5644 ret = -1;
5645 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005646 nodes = nodes->next;
5647 }
5648 return (ret);
5649}
5650
5651/**
5652 * xmlRelaxNGCheckReference:
5653 * @ref: the ref
5654 * @ctxt: a Relax-NG parser context
5655 * @name: the name associated to the defines
5656 *
5657 * Applies the 4.17. combine attribute rule for all the define
5658 * element of a given grammar using the same name.
5659 */
5660static void
5661xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
Daniel Veillard4c004142003-10-07 11:33:24 +00005662 xmlRelaxNGParserCtxtPtr ctxt,
5663 const xmlChar * name)
5664{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005665 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005666 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005667
5668 grammar = ctxt->grammar;
5669 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005670 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5671 "Internal error: no grammar in CheckReference %s\n",
5672 name, NULL);
5673 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005674 }
5675 if (ref->content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005676 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5677 "Internal error: reference has content in CheckReference %s\n",
5678 name, NULL);
5679 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005680 }
5681 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005682 def = xmlHashLookup(grammar->defs, name);
5683 if (def != NULL) {
5684 cur = ref;
5685 while (cur != NULL) {
5686 cur->content = def;
5687 cur = cur->nextHash;
5688 }
5689 } else {
5690 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5691 "Reference %s has no matching definition\n", name,
5692 NULL);
5693 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005694 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005695 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5696 "Reference %s has no matching definition\n", name,
5697 NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005698 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005699}
5700
5701/**
5702 * xmlRelaxNGCheckCombine:
5703 * @define: the define(s) list
5704 * @ctxt: a Relax-NG parser context
5705 * @name: the name associated to the defines
5706 *
5707 * Applies the 4.17. combine attribute rule for all the define
5708 * element of a given grammar using the same name.
5709 */
5710static void
5711xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
Daniel Veillard4c004142003-10-07 11:33:24 +00005712 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name)
5713{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005714 xmlChar *combine;
5715 int choiceOrInterleave = -1;
5716 int missing = 0;
5717 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5718
5719 if (define->nextHash == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005720 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005721 cur = define;
5722 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005723 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5724 if (combine != NULL) {
5725 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5726 if (choiceOrInterleave == -1)
5727 choiceOrInterleave = 1;
5728 else if (choiceOrInterleave == 0) {
5729 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5730 "Defines for %s use both 'choice' and 'interleave'\n",
5731 name, NULL);
5732 }
5733 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5734 if (choiceOrInterleave == -1)
5735 choiceOrInterleave = 0;
5736 else if (choiceOrInterleave == 1) {
5737 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5738 "Defines for %s use both 'choice' and 'interleave'\n",
5739 name, NULL);
5740 }
5741 } else {
5742 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
5743 "Defines for %s use unknown combine value '%s''\n",
5744 name, combine);
5745 }
5746 xmlFree(combine);
5747 } else {
5748 if (missing == 0)
5749 missing = 1;
5750 else {
5751 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
5752 "Some defines for %s needs the combine attribute\n",
5753 name, NULL);
5754 }
5755 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005756
Daniel Veillard4c004142003-10-07 11:33:24 +00005757 cur = cur->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005758 }
5759#ifdef DEBUG
5760 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005761 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5762 name, choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005763#endif
5764 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005765 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005766 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005767 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005768 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005769 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005770 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005771 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005772 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005773 tmp = define;
5774 last = NULL;
5775 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005776 if (tmp->content != NULL) {
5777 if (tmp->content->next != NULL) {
5778 /*
5779 * we need first to create a wrapper.
5780 */
5781 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5782 if (tmp2 == NULL)
5783 break;
5784 tmp2->type = XML_RELAXNG_GROUP;
5785 tmp2->content = tmp->content;
5786 } else {
5787 tmp2 = tmp->content;
5788 }
5789 if (last == NULL) {
5790 cur->content = tmp2;
5791 } else {
5792 last->next = tmp2;
5793 }
5794 last = tmp2;
5795 }
5796 tmp->content = cur;
5797 tmp = tmp->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005798 }
5799 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005800 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005801 if (ctxt->interleaves == NULL)
5802 ctxt->interleaves = xmlHashCreate(10);
5803 if (ctxt->interleaves == NULL) {
5804 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5805 "Failed to create interleaves hash table\n", NULL,
5806 NULL);
5807 } else {
5808 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005809
Daniel Veillard4c004142003-10-07 11:33:24 +00005810 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5811 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5812 0) {
5813 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5814 "Failed to add %s to hash table\n",
5815 (const xmlChar *) tmpname, NULL);
5816 }
5817 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005818 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005819}
5820
5821/**
5822 * xmlRelaxNGCombineStart:
5823 * @ctxt: a Relax-NG parser context
5824 * @grammar: the grammar
5825 *
5826 * Applies the 4.17. combine rule for all the start
5827 * element of a given grammar.
5828 */
5829static void
5830xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005831 xmlRelaxNGGrammarPtr grammar)
5832{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005833 xmlRelaxNGDefinePtr starts;
5834 xmlChar *combine;
5835 int choiceOrInterleave = -1;
5836 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005837 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005838
Daniel Veillard2df2de22003-02-17 23:34:33 +00005839 starts = grammar->start;
5840 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00005841 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005842 cur = starts;
5843 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005844 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5845 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5846 combine = NULL;
5847 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
5848 "Internal error: start element not found\n", NULL,
5849 NULL);
5850 } else {
5851 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5852 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005853
Daniel Veillard4c004142003-10-07 11:33:24 +00005854 if (combine != NULL) {
5855 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5856 if (choiceOrInterleave == -1)
5857 choiceOrInterleave = 1;
5858 else if (choiceOrInterleave == 0) {
5859 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5860 "<start> use both 'choice' and 'interleave'\n",
5861 NULL, NULL);
5862 }
5863 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5864 if (choiceOrInterleave == -1)
5865 choiceOrInterleave = 0;
5866 else if (choiceOrInterleave == 1) {
5867 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5868 "<start> use both 'choice' and 'interleave'\n",
5869 NULL, NULL);
5870 }
5871 } else {
5872 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
5873 "<start> uses unknown combine value '%s''\n",
5874 combine, NULL);
5875 }
5876 xmlFree(combine);
5877 } else {
5878 if (missing == 0)
5879 missing = 1;
5880 else {
5881 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
5882 "Some <start> element miss the combine attribute\n",
5883 NULL, NULL);
5884 }
5885 }
5886
5887 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005888 }
5889#ifdef DEBUG
5890 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005891 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5892 choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005893#endif
5894 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005895 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005896 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005897 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005898 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005899 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005900 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005901 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005902 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005903 cur->content = grammar->start;
5904 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005905 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005906 if (ctxt->interleaves == NULL)
5907 ctxt->interleaves = xmlHashCreate(10);
5908 if (ctxt->interleaves == NULL) {
5909 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5910 "Failed to create interleaves hash table\n", NULL,
5911 NULL);
5912 } else {
5913 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005914
Daniel Veillard4c004142003-10-07 11:33:24 +00005915 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5916 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5917 0) {
5918 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5919 "Failed to add %s to hash table\n",
5920 (const xmlChar *) tmpname, NULL);
5921 }
5922 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005923 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005924}
5925
5926/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005927 * xmlRelaxNGCheckCycles:
5928 * @ctxt: a Relax-NG parser context
5929 * @nodes: grammar children nodes
5930 * @depth: the counter
5931 *
5932 * Check for cycles.
5933 *
5934 * Returns 0 if check passed, and -1 in case of error
5935 */
5936static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005937xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5938 xmlRelaxNGDefinePtr cur, int depth)
5939{
Daniel Veillardd4310742003-02-18 21:12:46 +00005940 int ret = 0;
5941
5942 while ((ret == 0) && (cur != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005943 if ((cur->type == XML_RELAXNG_REF) ||
5944 (cur->type == XML_RELAXNG_PARENTREF)) {
5945 if (cur->depth == -1) {
5946 cur->depth = depth;
5947 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5948 cur->depth = -2;
5949 } else if (depth == cur->depth) {
5950 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
5951 "Detected a cycle in %s references\n",
5952 cur->name, NULL);
5953 return (-1);
5954 }
5955 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5956 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5957 } else {
5958 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5959 }
5960 cur = cur->next;
Daniel Veillardd4310742003-02-18 21:12:46 +00005961 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005962 return (ret);
Daniel Veillardd4310742003-02-18 21:12:46 +00005963}
5964
5965/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005966 * xmlRelaxNGTryUnlink:
5967 * @ctxt: a Relax-NG parser context
5968 * @cur: the definition to unlink
5969 * @parent: the parent definition
5970 * @prev: the previous sibling definition
5971 *
5972 * Try to unlink a definition. If not possble make it a NOOP
5973 *
5974 * Returns the new prev definition
5975 */
5976static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005977xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5978 xmlRelaxNGDefinePtr cur,
5979 xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
5980{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005981 if (prev != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005982 prev->next = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005983 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005984 if (parent != NULL) {
5985 if (parent->content == cur)
5986 parent->content = cur->next;
5987 else if (parent->attrs == cur)
5988 parent->attrs = cur->next;
5989 else if (parent->nameClass == cur)
5990 parent->nameClass = cur->next;
5991 } else {
5992 cur->type = XML_RELAXNG_NOOP;
5993 prev = cur;
5994 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005995 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005996 return (prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005997}
5998
5999/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006000 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006001 * @ctxt: a Relax-NG parser context
6002 * @nodes: grammar children nodes
6003 *
6004 * Check for simplification of empty and notAllowed
6005 */
6006static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006007xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
6008 xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
6009{
Daniel Veillardfd573f12003-03-16 17:52:32 +00006010 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006011
Daniel Veillardfd573f12003-03-16 17:52:32 +00006012 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006013 if ((cur->type == XML_RELAXNG_REF) ||
6014 (cur->type == XML_RELAXNG_PARENTREF)) {
6015 if (cur->depth != -3) {
6016 cur->depth = -3;
6017 xmlRelaxNGSimplify(ctxt, cur->content, cur);
6018 }
6019 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6020 cur->parent = parent;
6021 if ((parent != NULL) &&
6022 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6023 (parent->type == XML_RELAXNG_LIST) ||
6024 (parent->type == XML_RELAXNG_GROUP) ||
6025 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6026 (parent->type == XML_RELAXNG_ONEORMORE) ||
6027 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6028 parent->type = XML_RELAXNG_NOT_ALLOWED;
6029 break;
6030 }
6031 if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
6032 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6033 } else
6034 prev = cur;
6035 } else if (cur->type == XML_RELAXNG_EMPTY) {
6036 cur->parent = parent;
6037 if ((parent != NULL) &&
6038 ((parent->type == XML_RELAXNG_ONEORMORE) ||
6039 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6040 parent->type = XML_RELAXNG_EMPTY;
6041 break;
6042 }
6043 if ((parent != NULL) &&
6044 ((parent->type == XML_RELAXNG_GROUP) ||
6045 (parent->type == XML_RELAXNG_INTERLEAVE))) {
6046 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6047 } else
6048 prev = cur;
6049 } else {
6050 cur->parent = parent;
6051 if (cur->content != NULL)
6052 xmlRelaxNGSimplify(ctxt, cur->content, cur);
6053 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
6054 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
6055 if (cur->nameClass != NULL)
6056 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
6057 /*
6058 * On Elements, try to move attribute only generating rules on
6059 * the attrs rules.
6060 */
6061 if (cur->type == XML_RELAXNG_ELEMENT) {
6062 int attronly;
6063 xmlRelaxNGDefinePtr tmp, pre;
Daniel Veillardce192eb2003-04-16 15:58:05 +00006064
Daniel Veillard4c004142003-10-07 11:33:24 +00006065 while (cur->content != NULL) {
6066 attronly =
6067 xmlRelaxNGGenerateAttributes(ctxt, cur->content);
6068 if (attronly == 1) {
6069 /*
6070 * migrate cur->content to attrs
6071 */
6072 tmp = cur->content;
6073 cur->content = tmp->next;
6074 tmp->next = cur->attrs;
6075 cur->attrs = tmp;
6076 } else {
6077 /*
6078 * cur->content can generate elements or text
6079 */
6080 break;
6081 }
6082 }
6083 pre = cur->content;
6084 while ((pre != NULL) && (pre->next != NULL)) {
6085 tmp = pre->next;
6086 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
6087 if (attronly == 1) {
6088 /*
6089 * migrate tmp to attrs
6090 */
6091 pre->next = tmp->next;
6092 tmp->next = cur->attrs;
6093 cur->attrs = tmp;
6094 } else {
6095 pre = tmp;
6096 }
6097 }
6098 }
6099 /*
6100 * This may result in a simplification
6101 */
6102 if ((cur->type == XML_RELAXNG_GROUP) ||
6103 (cur->type == XML_RELAXNG_INTERLEAVE)) {
6104 if (cur->content == NULL)
6105 cur->type = XML_RELAXNG_EMPTY;
6106 else if (cur->content->next == NULL) {
6107 if ((parent == NULL) && (prev == NULL)) {
6108 cur->type = XML_RELAXNG_NOOP;
6109 } else if (prev == NULL) {
6110 parent->content = cur->content;
6111 cur->content->next = cur->next;
6112 cur = cur->content;
6113 } else {
6114 cur->content->next = cur->next;
6115 prev->next = cur->content;
6116 cur = cur->content;
6117 }
6118 }
6119 }
6120 /*
6121 * the current node may have been transformed back
6122 */
6123 if ((cur->type == XML_RELAXNG_EXCEPT) &&
6124 (cur->content != NULL) &&
6125 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
6126 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6127 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6128 if ((parent != NULL) &&
6129 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6130 (parent->type == XML_RELAXNG_LIST) ||
6131 (parent->type == XML_RELAXNG_GROUP) ||
6132 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6133 (parent->type == XML_RELAXNG_ONEORMORE) ||
6134 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6135 parent->type = XML_RELAXNG_NOT_ALLOWED;
6136 break;
6137 }
6138 if ((parent != NULL) &&
6139 (parent->type == XML_RELAXNG_CHOICE)) {
6140 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6141 } else
6142 prev = cur;
6143 } else if (cur->type == XML_RELAXNG_EMPTY) {
6144 if ((parent != NULL) &&
6145 ((parent->type == XML_RELAXNG_ONEORMORE) ||
6146 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6147 parent->type = XML_RELAXNG_EMPTY;
6148 break;
6149 }
6150 if ((parent != NULL) &&
6151 ((parent->type == XML_RELAXNG_GROUP) ||
6152 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6153 (parent->type == XML_RELAXNG_CHOICE))) {
6154 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6155 } else
6156 prev = cur;
6157 } else {
6158 prev = cur;
6159 }
6160 }
6161 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006162 }
6163}
6164
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006165/**
6166 * xmlRelaxNGGroupContentType:
6167 * @ct1: the first content type
6168 * @ct2: the second content type
6169 *
6170 * Try to group 2 content types
6171 *
6172 * Returns the content type
6173 */
6174static xmlRelaxNGContentType
6175xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006176 xmlRelaxNGContentType ct2)
6177{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006178 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006179 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6180 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006181 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006182 return (ct2);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006183 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006184 return (ct1);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006185 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00006186 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6187 return (XML_RELAXNG_CONTENT_COMPLEX);
6188 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006189}
6190
6191/**
6192 * xmlRelaxNGMaxContentType:
6193 * @ct1: the first content type
6194 * @ct2: the second content type
6195 *
6196 * Compute the max content-type
6197 *
6198 * Returns the content type
6199 */
6200static xmlRelaxNGContentType
6201xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006202 xmlRelaxNGContentType ct2)
6203{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006204 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006205 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6206 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006207 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006208 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6209 return (XML_RELAXNG_CONTENT_SIMPLE);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006210 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006211 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6212 return (XML_RELAXNG_CONTENT_COMPLEX);
6213 return (XML_RELAXNG_CONTENT_EMPTY);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006214}
Daniel Veillard77648bb2003-02-20 15:03:22 +00006215
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006216/**
6217 * xmlRelaxNGCheckRules:
6218 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006219 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00006220 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00006221 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006222 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006223 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006224 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006225 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006226 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006227static xmlRelaxNGContentType
Daniel Veillard4c004142003-10-07 11:33:24 +00006228xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6229 xmlRelaxNGDefinePtr cur, int flags,
6230 xmlRelaxNGType ptype)
6231{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006232 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006233 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006234
Daniel Veillardfd573f12003-03-16 17:52:32 +00006235 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006236 ret = XML_RELAXNG_CONTENT_EMPTY;
6237 if ((cur->type == XML_RELAXNG_REF) ||
6238 (cur->type == XML_RELAXNG_PARENTREF)) {
Daniel Veillard63d68a32005-03-31 13:50:00 +00006239 /*
6240 * This should actually be caught by list//element(ref) at the
6241 * element boundaries, c.f. Bug #159968 local refs are dropped
6242 * in step 4.19.
6243 */
6244#if 0
Daniel Veillard4c004142003-10-07 11:33:24 +00006245 if (flags & XML_RELAXNG_IN_LIST) {
6246 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6247 "Found forbidden pattern list//ref\n", NULL,
6248 NULL);
6249 }
Daniel Veillard63d68a32005-03-31 13:50:00 +00006250#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00006251 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6252 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6253 "Found forbidden pattern data/except//ref\n",
6254 NULL, NULL);
6255 }
Daniel Veillard81c51e12009-08-14 18:52:10 +02006256 if (cur->content == NULL) {
6257 if (cur->type == XML_RELAXNG_PARENTREF)
6258 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
6259 "Internal found no define for parent refs\n",
6260 NULL, NULL);
6261 else
6262 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
6263 "Internal found no define for ref %s\n",
Daniel Veillarda4f27cb2009-08-21 17:34:17 +02006264 (cur->name ? cur->name: BAD_CAST "null"), NULL);
Daniel Veillard81c51e12009-08-14 18:52:10 +02006265 }
Daniel Veillard4c004142003-10-07 11:33:24 +00006266 if (cur->depth > -4) {
6267 cur->depth = -4;
6268 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6269 flags, cur->type);
6270 cur->depth = ret - 15;
6271 } else if (cur->depth == -4) {
6272 ret = XML_RELAXNG_CONTENT_COMPLEX;
6273 } else {
6274 ret = (xmlRelaxNGContentType) (cur->depth + 15);
6275 }
6276 } else if (cur->type == XML_RELAXNG_ELEMENT) {
6277 /*
6278 * The 7.3 Attribute derivation rule for groups is plugged there
6279 */
6280 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6281 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6282 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6283 "Found forbidden pattern data/except//element(ref)\n",
6284 NULL, NULL);
6285 }
6286 if (flags & XML_RELAXNG_IN_LIST) {
6287 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6288 "Found forbidden pattern list//element(ref)\n",
6289 NULL, NULL);
6290 }
6291 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6292 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6293 "Found forbidden pattern attribute//element(ref)\n",
6294 NULL, NULL);
6295 }
6296 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6297 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6298 "Found forbidden pattern attribute//element(ref)\n",
6299 NULL, NULL);
6300 }
6301 /*
6302 * reset since in the simple form elements are only child
6303 * of grammar/define
6304 */
6305 nflags = 0;
6306 ret =
6307 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6308 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6309 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6310 "Element %s attributes have a content type error\n",
6311 cur->name, NULL);
6312 }
6313 ret =
6314 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6315 cur->type);
6316 if (ret == XML_RELAXNG_CONTENT_ERROR) {
6317 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6318 "Element %s has a content type error\n",
6319 cur->name, NULL);
6320 } else {
6321 ret = XML_RELAXNG_CONTENT_COMPLEX;
6322 }
6323 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6324 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6325 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6326 "Found forbidden pattern attribute//attribute\n",
6327 NULL, NULL);
6328 }
6329 if (flags & XML_RELAXNG_IN_LIST) {
6330 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6331 "Found forbidden pattern list//attribute\n",
6332 NULL, NULL);
6333 }
6334 if (flags & XML_RELAXNG_IN_OOMGROUP) {
6335 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6336 "Found forbidden pattern oneOrMore//group//attribute\n",
6337 NULL, NULL);
6338 }
6339 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6340 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6341 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6342 NULL, NULL);
6343 }
6344 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6345 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6346 "Found forbidden pattern data/except//attribute\n",
6347 NULL, NULL);
6348 }
6349 if (flags & XML_RELAXNG_IN_START) {
6350 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6351 "Found forbidden pattern start//attribute\n",
6352 NULL, NULL);
6353 }
6354 if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6355 && (cur->name == NULL)) {
6356 if (cur->ns == NULL) {
6357 xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6358 "Found anyName attribute without oneOrMore ancestor\n",
6359 NULL, NULL);
6360 } else {
6361 xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6362 "Found nsName attribute without oneOrMore ancestor\n",
6363 NULL, NULL);
6364 }
6365 }
6366 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6367 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6368 ret = XML_RELAXNG_CONTENT_EMPTY;
6369 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6370 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6371 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6372 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6373 "Found forbidden pattern data/except//oneOrMore\n",
6374 NULL, NULL);
6375 }
6376 if (flags & XML_RELAXNG_IN_START) {
6377 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6378 "Found forbidden pattern start//oneOrMore\n",
6379 NULL, NULL);
6380 }
6381 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6382 ret =
6383 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6384 cur->type);
6385 ret = xmlRelaxNGGroupContentType(ret, ret);
6386 } else if (cur->type == XML_RELAXNG_LIST) {
6387 if (flags & XML_RELAXNG_IN_LIST) {
6388 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6389 "Found forbidden pattern list//list\n", NULL,
6390 NULL);
6391 }
6392 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6393 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6394 "Found forbidden pattern data/except//list\n",
6395 NULL, NULL);
6396 }
6397 if (flags & XML_RELAXNG_IN_START) {
6398 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6399 "Found forbidden pattern start//list\n", NULL,
6400 NULL);
6401 }
6402 nflags = flags | XML_RELAXNG_IN_LIST;
6403 ret =
6404 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6405 cur->type);
6406 } else if (cur->type == XML_RELAXNG_GROUP) {
6407 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6408 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6409 "Found forbidden pattern data/except//group\n",
6410 NULL, NULL);
6411 }
6412 if (flags & XML_RELAXNG_IN_START) {
6413 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6414 "Found forbidden pattern start//group\n", NULL,
6415 NULL);
6416 }
6417 if (flags & XML_RELAXNG_IN_ONEORMORE)
6418 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6419 else
6420 nflags = flags;
6421 ret =
6422 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6423 cur->type);
6424 /*
6425 * The 7.3 Attribute derivation rule for groups is plugged there
6426 */
6427 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6428 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6429 if (flags & XML_RELAXNG_IN_LIST) {
6430 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6431 "Found forbidden pattern list//interleave\n",
6432 NULL, NULL);
6433 }
6434 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6435 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6436 "Found forbidden pattern data/except//interleave\n",
6437 NULL, NULL);
6438 }
6439 if (flags & XML_RELAXNG_IN_START) {
6440 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6441 "Found forbidden pattern start//interleave\n",
6442 NULL, NULL);
6443 }
6444 if (flags & XML_RELAXNG_IN_ONEORMORE)
6445 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6446 else
6447 nflags = flags;
6448 ret =
6449 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6450 cur->type);
6451 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6452 if ((cur->parent != NULL) &&
6453 (cur->parent->type == XML_RELAXNG_DATATYPE))
6454 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6455 else
6456 nflags = flags;
6457 ret =
6458 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6459 cur->type);
6460 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6461 if (flags & XML_RELAXNG_IN_START) {
6462 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6463 "Found forbidden pattern start//data\n", NULL,
6464 NULL);
6465 }
6466 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6467 ret = XML_RELAXNG_CONTENT_SIMPLE;
6468 } else if (cur->type == XML_RELAXNG_VALUE) {
6469 if (flags & XML_RELAXNG_IN_START) {
6470 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6471 "Found forbidden pattern start//value\n", NULL,
6472 NULL);
6473 }
6474 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6475 ret = XML_RELAXNG_CONTENT_SIMPLE;
6476 } else if (cur->type == XML_RELAXNG_TEXT) {
6477 if (flags & XML_RELAXNG_IN_LIST) {
6478 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6479 "Found forbidden pattern list//text\n", NULL,
6480 NULL);
6481 }
6482 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6483 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6484 "Found forbidden pattern data/except//text\n",
6485 NULL, NULL);
6486 }
6487 if (flags & XML_RELAXNG_IN_START) {
6488 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6489 "Found forbidden pattern start//text\n", NULL,
6490 NULL);
6491 }
6492 ret = XML_RELAXNG_CONTENT_COMPLEX;
6493 } else if (cur->type == XML_RELAXNG_EMPTY) {
6494 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6495 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6496 "Found forbidden pattern data/except//empty\n",
6497 NULL, NULL);
6498 }
6499 if (flags & XML_RELAXNG_IN_START) {
6500 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6501 "Found forbidden pattern start//empty\n", NULL,
6502 NULL);
6503 }
6504 ret = XML_RELAXNG_CONTENT_EMPTY;
6505 } else if (cur->type == XML_RELAXNG_CHOICE) {
6506 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6507 ret =
6508 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6509 } else {
6510 ret =
6511 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6512 }
6513 cur = cur->next;
6514 if (ptype == XML_RELAXNG_GROUP) {
6515 val = xmlRelaxNGGroupContentType(val, ret);
6516 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6517 tmp = xmlRelaxNGGroupContentType(val, ret);
6518 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6519 tmp = xmlRelaxNGMaxContentType(val, ret);
6520 } else if (ptype == XML_RELAXNG_CHOICE) {
6521 val = xmlRelaxNGMaxContentType(val, ret);
6522 } else if (ptype == XML_RELAXNG_LIST) {
6523 val = XML_RELAXNG_CONTENT_SIMPLE;
6524 } else if (ptype == XML_RELAXNG_EXCEPT) {
6525 if (ret == XML_RELAXNG_CONTENT_ERROR)
6526 val = XML_RELAXNG_CONTENT_ERROR;
6527 else
6528 val = XML_RELAXNG_CONTENT_SIMPLE;
6529 } else {
6530 val = xmlRelaxNGGroupContentType(val, ret);
6531 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006532
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006533 }
Daniel Veillard4c004142003-10-07 11:33:24 +00006534 return (val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006535}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006536
6537/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006538 * xmlRelaxNGParseGrammar:
6539 * @ctxt: a Relax-NG parser context
6540 * @nodes: grammar children nodes
6541 *
6542 * parse a Relax-NG <grammar> node
6543 *
6544 * Returns the internal xmlRelaxNGGrammarPtr built or
6545 * NULL in case of error
6546 */
6547static xmlRelaxNGGrammarPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006548xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6549{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006550 xmlRelaxNGGrammarPtr ret, tmp, old;
6551
Daniel Veillardc482e262003-02-26 14:48:48 +00006552#ifdef DEBUG_GRAMMAR
6553 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6554#endif
6555
Daniel Veillard6eadf632003-01-23 18:29:16 +00006556 ret = xmlRelaxNGNewGrammar(ctxt);
6557 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006558 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006559
6560 /*
6561 * Link the new grammar in the tree
6562 */
6563 ret->parent = ctxt->grammar;
6564 if (ctxt->grammar != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006565 tmp = ctxt->grammar->children;
6566 if (tmp == NULL) {
6567 ctxt->grammar->children = ret;
6568 } else {
6569 while (tmp->next != NULL)
6570 tmp = tmp->next;
6571 tmp->next = ret;
6572 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006573 }
6574
6575 old = ctxt->grammar;
6576 ctxt->grammar = ret;
6577 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6578 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006579 if (ctxt->grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006580 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6581 "Failed to parse <grammar> content\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006582 } else if (ctxt->grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006583 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6584 "Element <grammar> has no <start>\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006585 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006586
6587 /*
6588 * Apply 4.17 mergingd rules to defines and starts
6589 */
6590 xmlRelaxNGCombineStart(ctxt, ret);
6591 if (ret->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006592 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6593 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006594 }
6595
6596 /*
6597 * link together defines and refs in this grammar
6598 */
6599 if (ret->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006600 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6601 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006602 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006603
Daniel Veillard81c51e12009-08-14 18:52:10 +02006604
Daniel Veillard25a1ce92008-06-02 16:04:12 +00006605 /* @@@@ */
6606
Daniel Veillard6eadf632003-01-23 18:29:16 +00006607 ctxt->grammar = old;
Daniel Veillard4c004142003-10-07 11:33:24 +00006608 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006609}
6610
6611/**
6612 * xmlRelaxNGParseDocument:
6613 * @ctxt: a Relax-NG parser context
6614 * @node: the root node of the RelaxNG schema
6615 *
6616 * parse a Relax-NG definition resource and build an internal
6617 * xmlRelaxNG struture which can be used to validate instances.
6618 *
6619 * Returns the internal XML RelaxNG structure built or
6620 * NULL in case of error
6621 */
6622static xmlRelaxNGPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006623xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6624{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006625 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006626 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006627 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006628
6629 if ((ctxt == NULL) || (node == NULL))
6630 return (NULL);
6631
6632 schema = xmlRelaxNGNewRelaxNG(ctxt);
6633 if (schema == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006634 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006635
Daniel Veillard276be4a2003-01-24 01:03:34 +00006636 olddefine = ctxt->define;
6637 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006638 if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006639 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006640 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006641 xmlRelaxNGGrammarPtr tmp, ret;
Daniel Veillardc482e262003-02-26 14:48:48 +00006642
Daniel Veillard4c004142003-10-07 11:33:24 +00006643 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6644 if (schema->topgrammar == NULL) {
6645 return (schema);
6646 }
6647 /*
6648 * Link the new grammar in the tree
6649 */
6650 ret->parent = ctxt->grammar;
6651 if (ctxt->grammar != NULL) {
6652 tmp = ctxt->grammar->children;
6653 if (tmp == NULL) {
6654 ctxt->grammar->children = ret;
6655 } else {
6656 while (tmp->next != NULL)
6657 tmp = tmp->next;
6658 tmp->next = ret;
6659 }
6660 }
6661 old = ctxt->grammar;
6662 ctxt->grammar = ret;
6663 xmlRelaxNGParseStart(ctxt, node);
6664 if (old != NULL)
6665 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006666 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006667 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006668 if (schema->topgrammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006669 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6670 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6671 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6672 while ((schema->topgrammar->start != NULL) &&
6673 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6674 (schema->topgrammar->start->next != NULL))
6675 schema->topgrammar->start =
6676 schema->topgrammar->start->content;
6677 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6678 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6679 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006680 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006681#ifdef DEBUG
6682 if (schema == NULL)
6683 xmlGenericError(xmlGenericErrorContext,
6684 "xmlRelaxNGParseDocument() failed\n");
6685#endif
6686
6687 return (schema);
6688}
6689
6690/************************************************************************
6691 * *
6692 * Reading RelaxNGs *
6693 * *
6694 ************************************************************************/
6695
6696/**
6697 * xmlRelaxNGNewParserCtxt:
6698 * @URL: the location of the schema
6699 *
6700 * Create an XML RelaxNGs parse context for that file/resource expected
6701 * to contain an XML RelaxNGs file.
6702 *
6703 * Returns the parser context or NULL in case of error
6704 */
6705xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006706xmlRelaxNGNewParserCtxt(const char *URL)
6707{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006708 xmlRelaxNGParserCtxtPtr ret;
6709
6710 if (URL == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006711 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006712
Daniel Veillard4c004142003-10-07 11:33:24 +00006713 ret =
6714 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006715 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006716 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006717 return (NULL);
6718 }
6719 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard4c004142003-10-07 11:33:24 +00006720 ret->URL = xmlStrdup((const xmlChar *) URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006721 ret->error = xmlGenericError;
6722 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006723 return (ret);
6724}
6725
6726/**
6727 * xmlRelaxNGNewMemParserCtxt:
6728 * @buffer: a pointer to a char array containing the schemas
6729 * @size: the size of the array
6730 *
6731 * Create an XML RelaxNGs parse context for that memory buffer expected
6732 * to contain an XML RelaxNGs file.
6733 *
6734 * Returns the parser context or NULL in case of error
6735 */
6736xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006737xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6738{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006739 xmlRelaxNGParserCtxtPtr ret;
6740
6741 if ((buffer == NULL) || (size <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00006742 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006743
Daniel Veillard4c004142003-10-07 11:33:24 +00006744 ret =
6745 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006746 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006747 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006748 return (NULL);
6749 }
6750 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6751 ret->buffer = buffer;
6752 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006753 ret->error = xmlGenericError;
6754 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006755 return (ret);
6756}
6757
6758/**
Daniel Veillard33300b42003-04-17 09:09:19 +00006759 * xmlRelaxNGNewDocParserCtxt:
6760 * @doc: a preparsed document tree
6761 *
6762 * Create an XML RelaxNGs parser context for that document.
6763 * Note: since the process of compiling a RelaxNG schemas modifies the
6764 * document, the @doc parameter is duplicated internally.
6765 *
6766 * Returns the parser context or NULL in case of error
6767 */
6768xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006769xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6770{
Daniel Veillard33300b42003-04-17 09:09:19 +00006771 xmlRelaxNGParserCtxtPtr ret;
6772 xmlDocPtr copy;
6773
6774 if (doc == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006775 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006776 copy = xmlCopyDoc(doc, 1);
6777 if (copy == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006778 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006779
Daniel Veillard4c004142003-10-07 11:33:24 +00006780 ret =
6781 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard33300b42003-04-17 09:09:19 +00006782 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006783 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard33300b42003-04-17 09:09:19 +00006784 return (NULL);
6785 }
6786 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6787 ret->document = copy;
Daniel Veillard42595322004-11-08 10:52:06 +00006788 ret->freedoc = 1;
Daniel Veillard33300b42003-04-17 09:09:19 +00006789 ret->userData = xmlGenericErrorContext;
6790 return (ret);
6791}
6792
6793/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006794 * xmlRelaxNGFreeParserCtxt:
6795 * @ctxt: the schema parser context
6796 *
6797 * Free the resources associated to the schema parser context
6798 */
6799void
Daniel Veillard4c004142003-10-07 11:33:24 +00006800xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6801{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006802 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006803 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006804 if (ctxt->URL != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006805 xmlFree(ctxt->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006806 if (ctxt->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006807 xmlRelaxNGFreeDocument(ctxt->doc);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006808 if (ctxt->interleaves != NULL)
6809 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006810 if (ctxt->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006811 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006812 if (ctxt->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006813 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006814 if (ctxt->docTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006815 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006816 if (ctxt->incTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006817 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006818 if (ctxt->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006819 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +00006820
Daniel Veillard4c004142003-10-07 11:33:24 +00006821 for (i = 0; i < ctxt->defNr; i++)
6822 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6823 xmlFree(ctxt->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006824 }
Daniel Veillard42595322004-11-08 10:52:06 +00006825 if ((ctxt->document != NULL) && (ctxt->freedoc))
6826 xmlFreeDoc(ctxt->document);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006827 xmlFree(ctxt);
6828}
6829
Daniel Veillard6eadf632003-01-23 18:29:16 +00006830/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006831 * xmlRelaxNGNormExtSpace:
6832 * @value: a value
6833 *
6834 * Removes the leading and ending spaces of the value
6835 * The string is modified "in situ"
6836 */
6837static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006838xmlRelaxNGNormExtSpace(xmlChar * value)
6839{
Daniel Veillardd2298792003-02-14 16:54:11 +00006840 xmlChar *start = value;
6841 xmlChar *cur = value;
Daniel Veillardd2298792003-02-14 16:54:11 +00006842
Daniel Veillard4c004142003-10-07 11:33:24 +00006843 if (value == NULL)
6844 return;
6845
William M. Brack76e95df2003-10-18 16:20:14 +00006846 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006847 cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +00006848 if (cur == start) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006849 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006850 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006851 cur++;
6852 if (*cur == 0)
6853 return;
6854 start = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006855 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006856 cur++;
6857 if (*cur == 0) {
6858 *start = 0;
6859 return;
6860 }
6861 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006862 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006863 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006864 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006865 *start++ = *cur++;
6866 if (*cur == 0) {
6867 *start = 0;
6868 return;
6869 }
6870 /* don't try to normalize the inner spaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006871 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006872 cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006873 if (*cur == 0) {
6874 *start = 0;
6875 return;
6876 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00006877 *start++ = *cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006878 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006879 }
6880}
6881
6882/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006883 * xmlRelaxNGCleanupAttributes:
Daniel Veillardd2298792003-02-14 16:54:11 +00006884 * @ctxt: a Relax-NG parser context
6885 * @node: a Relax-NG node
6886 *
6887 * Check all the attributes on the given node
6888 */
6889static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006890xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6891{
Daniel Veillardd2298792003-02-14 16:54:11 +00006892 xmlAttrPtr cur, next;
6893
6894 cur = node->properties;
6895 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006896 next = cur->next;
6897 if ((cur->ns == NULL) ||
6898 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6899 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6900 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6901 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6902 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6903 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6904 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6905 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6906 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6907 "Attribute %s is not allowed on %s\n",
6908 cur->name, node->name);
6909 }
6910 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6911 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6912 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6913 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6914 "Attribute %s is not allowed on %s\n",
6915 cur->name, node->name);
6916 }
6917 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6918 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6919 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6920 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6921 "Attribute %s is not allowed on %s\n",
6922 cur->name, node->name);
6923 }
6924 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6925 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6926 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6927 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6928 "Attribute %s is not allowed on %s\n",
6929 cur->name, node->name);
6930 }
6931 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6932 xmlChar *val;
6933 xmlURIPtr uri;
Daniel Veillardd2298792003-02-14 16:54:11 +00006934
Daniel Veillard4c004142003-10-07 11:33:24 +00006935 val = xmlNodeListGetString(node->doc, cur->children, 1);
6936 if (val != NULL) {
6937 if (val[0] != 0) {
6938 uri = xmlParseURI((const char *) val);
6939 if (uri == NULL) {
6940 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
6941 "Attribute %s contains invalid URI %s\n",
6942 cur->name, val);
6943 } else {
6944 if (uri->scheme == NULL) {
6945 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
6946 "Attribute %s URI %s is not absolute\n",
6947 cur->name, val);
6948 }
6949 if (uri->fragment != NULL) {
6950 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
6951 "Attribute %s URI %s has a fragment ID\n",
6952 cur->name, val);
6953 }
6954 xmlFreeURI(uri);
6955 }
6956 }
6957 xmlFree(val);
6958 }
6959 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6960 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
6961 "Unknown attribute %s on %s\n", cur->name,
6962 node->name);
6963 }
6964 }
6965 cur = next;
Daniel Veillardd2298792003-02-14 16:54:11 +00006966 }
6967}
6968
6969/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006970 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006971 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006972 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006973 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006974 * Cleanup the subtree from unwanted nodes for parsing, resolve
6975 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006976 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006977static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006978xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
6979{
Daniel Veillardc5312d72003-02-21 17:14:10 +00006980 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006981
Daniel Veillard6eadf632003-01-23 18:29:16 +00006982 delete = NULL;
6983 cur = root;
6984 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006985 if (delete != NULL) {
6986 xmlUnlinkNode(delete);
6987 xmlFreeNode(delete);
6988 delete = NULL;
6989 }
6990 if (cur->type == XML_ELEMENT_NODE) {
6991 /*
6992 * Simplification 4.1. Annotations
6993 */
6994 if ((cur->ns == NULL) ||
6995 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6996 if ((cur->parent != NULL) &&
6997 (cur->parent->type == XML_ELEMENT_NODE) &&
6998 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6999 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
7000 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
7001 xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
7002 "element %s doesn't allow foreign elements\n",
7003 cur->parent->name, NULL);
7004 }
7005 delete = cur;
7006 goto skip_children;
7007 } else {
7008 xmlRelaxNGCleanupAttributes(ctxt, cur);
7009 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
7010 xmlChar *href, *ns, *base, *URL;
7011 xmlRelaxNGDocumentPtr docu;
7012 xmlNodePtr tmp;
Daniel Veillard6dc91962004-03-22 19:10:02 +00007013 xmlURIPtr uri;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007014
Daniel Veillard4c004142003-10-07 11:33:24 +00007015 ns = xmlGetProp(cur, BAD_CAST "ns");
7016 if (ns == NULL) {
7017 tmp = cur->parent;
7018 while ((tmp != NULL) &&
7019 (tmp->type == XML_ELEMENT_NODE)) {
7020 ns = xmlGetProp(tmp, BAD_CAST "ns");
7021 if (ns != NULL)
7022 break;
7023 tmp = tmp->parent;
7024 }
7025 }
7026 href = xmlGetProp(cur, BAD_CAST "href");
7027 if (href == NULL) {
7028 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
7029 "xmlRelaxNGParse: externalRef has no href attribute\n",
7030 NULL, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00007031 if (ns != NULL)
7032 xmlFree(ns);
Daniel Veillard4c004142003-10-07 11:33:24 +00007033 delete = cur;
7034 goto skip_children;
7035 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00007036 uri = xmlParseURI((const char *) href);
7037 if (uri == NULL) {
7038 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7039 "Incorrect URI for externalRef %s\n",
7040 href, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00007041 if (ns != NULL)
7042 xmlFree(ns);
Daniel Veillard6dc91962004-03-22 19:10:02 +00007043 if (href != NULL)
7044 xmlFree(href);
7045 delete = cur;
7046 goto skip_children;
7047 }
7048 if (uri->fragment != NULL) {
7049 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7050 "Fragment forbidden in URI for externalRef %s\n",
7051 href, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00007052 if (ns != NULL)
7053 xmlFree(ns);
Daniel Veillard6dc91962004-03-22 19:10:02 +00007054 xmlFreeURI(uri);
7055 if (href != NULL)
7056 xmlFree(href);
7057 delete = cur;
7058 goto skip_children;
7059 }
7060 xmlFreeURI(uri);
Daniel Veillard4c004142003-10-07 11:33:24 +00007061 base = xmlNodeGetBase(cur->doc, cur);
7062 URL = xmlBuildURI(href, base);
7063 if (URL == NULL) {
7064 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7065 "Failed to compute URL for externalRef %s\n",
7066 href, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00007067 if (ns != NULL)
7068 xmlFree(ns);
Daniel Veillard4c004142003-10-07 11:33:24 +00007069 if (href != NULL)
7070 xmlFree(href);
7071 if (base != NULL)
7072 xmlFree(base);
7073 delete = cur;
7074 goto skip_children;
7075 }
7076 if (href != NULL)
7077 xmlFree(href);
7078 if (base != NULL)
7079 xmlFree(base);
7080 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
7081 if (docu == NULL) {
7082 xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
7083 "Failed to load externalRef %s\n", URL,
7084 NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00007085 if (ns != NULL)
7086 xmlFree(ns);
Daniel Veillard4c004142003-10-07 11:33:24 +00007087 xmlFree(URL);
7088 delete = cur;
7089 goto skip_children;
7090 }
7091 if (ns != NULL)
7092 xmlFree(ns);
7093 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00007094 cur->psvi = docu;
Daniel Veillard4c004142003-10-07 11:33:24 +00007095 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
7096 xmlChar *href, *ns, *base, *URL;
7097 xmlRelaxNGIncludePtr incl;
7098 xmlNodePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007099
Daniel Veillard4c004142003-10-07 11:33:24 +00007100 href = xmlGetProp(cur, BAD_CAST "href");
7101 if (href == NULL) {
7102 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
7103 "xmlRelaxNGParse: include has no href attribute\n",
7104 NULL, NULL);
7105 delete = cur;
7106 goto skip_children;
7107 }
7108 base = xmlNodeGetBase(cur->doc, cur);
7109 URL = xmlBuildURI(href, base);
7110 if (URL == NULL) {
7111 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7112 "Failed to compute URL for include %s\n",
7113 href, NULL);
7114 if (href != NULL)
7115 xmlFree(href);
7116 if (base != NULL)
7117 xmlFree(base);
7118 delete = cur;
7119 goto skip_children;
7120 }
7121 if (href != NULL)
7122 xmlFree(href);
7123 if (base != NULL)
7124 xmlFree(base);
7125 ns = xmlGetProp(cur, BAD_CAST "ns");
7126 if (ns == NULL) {
7127 tmp = cur->parent;
7128 while ((tmp != NULL) &&
7129 (tmp->type == XML_ELEMENT_NODE)) {
7130 ns = xmlGetProp(tmp, BAD_CAST "ns");
7131 if (ns != NULL)
7132 break;
7133 tmp = tmp->parent;
7134 }
7135 }
7136 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
7137 if (ns != NULL)
7138 xmlFree(ns);
7139 if (incl == NULL) {
7140 xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
7141 "Failed to load include %s\n", URL,
7142 NULL);
7143 xmlFree(URL);
7144 delete = cur;
7145 goto skip_children;
7146 }
7147 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00007148 cur->psvi = incl;
Daniel Veillard4c004142003-10-07 11:33:24 +00007149 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7150 (xmlStrEqual(cur->name, BAD_CAST "attribute")))
7151 {
7152 xmlChar *name, *ns;
7153 xmlNodePtr text = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007154
Daniel Veillard4c004142003-10-07 11:33:24 +00007155 /*
7156 * Simplification 4.8. name attribute of element
7157 * and attribute elements
7158 */
7159 name = xmlGetProp(cur, BAD_CAST "name");
7160 if (name != NULL) {
7161 if (cur->children == NULL) {
7162 text =
7163 xmlNewChild(cur, cur->ns, BAD_CAST "name",
7164 name);
7165 } else {
7166 xmlNodePtr node;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007167
Daniel Veillard03a53c32004-10-26 16:06:51 +00007168 node = xmlNewDocNode(cur->doc, cur->ns,
7169 BAD_CAST "name", NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00007170 if (node != NULL) {
7171 xmlAddPrevSibling(cur->children, node);
7172 text = xmlNewText(name);
7173 xmlAddChild(node, text);
7174 text = node;
7175 }
7176 }
7177 if (text == NULL) {
7178 xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7179 "Failed to create a name %s element\n",
7180 name, NULL);
7181 }
7182 xmlUnsetProp(cur, BAD_CAST "name");
7183 xmlFree(name);
7184 ns = xmlGetProp(cur, BAD_CAST "ns");
7185 if (ns != NULL) {
7186 if (text != NULL) {
7187 xmlSetProp(text, BAD_CAST "ns", ns);
7188 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7189 }
7190 xmlFree(ns);
7191 } else if (xmlStrEqual(cur->name,
7192 BAD_CAST "attribute")) {
7193 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7194 }
7195 }
7196 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7197 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7198 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7199 /*
7200 * Simplification 4.8. name attribute of element
7201 * and attribute elements
7202 */
7203 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7204 xmlNodePtr node;
7205 xmlChar *ns = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007206
Daniel Veillard4c004142003-10-07 11:33:24 +00007207 node = cur->parent;
7208 while ((node != NULL) &&
7209 (node->type == XML_ELEMENT_NODE)) {
7210 ns = xmlGetProp(node, BAD_CAST "ns");
7211 if (ns != NULL) {
7212 break;
7213 }
7214 node = node->parent;
7215 }
7216 if (ns == NULL) {
7217 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7218 } else {
7219 xmlSetProp(cur, BAD_CAST "ns", ns);
7220 xmlFree(ns);
7221 }
7222 }
7223 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7224 xmlChar *name, *local, *prefix;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007225
Daniel Veillard4c004142003-10-07 11:33:24 +00007226 /*
7227 * Simplification: 4.10. QNames
7228 */
7229 name = xmlNodeGetContent(cur);
7230 if (name != NULL) {
7231 local = xmlSplitQName2(name, &prefix);
7232 if (local != NULL) {
7233 xmlNsPtr ns;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007234
Daniel Veillard4c004142003-10-07 11:33:24 +00007235 ns = xmlSearchNs(cur->doc, cur, prefix);
7236 if (ns == NULL) {
7237 xmlRngPErr(ctxt, cur,
7238 XML_RNGP_PREFIX_UNDEFINED,
7239 "xmlRelaxNGParse: no namespace for prefix %s\n",
7240 prefix, NULL);
7241 } else {
7242 xmlSetProp(cur, BAD_CAST "ns",
7243 ns->href);
7244 xmlNodeSetContent(cur, local);
7245 }
7246 xmlFree(local);
7247 xmlFree(prefix);
7248 }
7249 xmlFree(name);
7250 }
7251 }
7252 /*
7253 * 4.16
7254 */
7255 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7256 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7257 xmlRngPErr(ctxt, cur,
7258 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7259 "Found nsName/except//nsName forbidden construct\n",
7260 NULL, NULL);
7261 }
7262 }
7263 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7264 (cur != root)) {
7265 int oldflags = ctxt->flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007266
Daniel Veillard4c004142003-10-07 11:33:24 +00007267 /*
7268 * 4.16
7269 */
7270 if ((cur->parent != NULL) &&
7271 (xmlStrEqual
7272 (cur->parent->name, BAD_CAST "anyName"))) {
7273 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7274 xmlRelaxNGCleanupTree(ctxt, cur);
7275 ctxt->flags = oldflags;
7276 goto skip_children;
7277 } else if ((cur->parent != NULL) &&
7278 (xmlStrEqual
7279 (cur->parent->name, BAD_CAST "nsName"))) {
7280 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7281 xmlRelaxNGCleanupTree(ctxt, cur);
7282 ctxt->flags = oldflags;
7283 goto skip_children;
7284 }
7285 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7286 /*
7287 * 4.16
7288 */
7289 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7290 xmlRngPErr(ctxt, cur,
7291 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7292 "Found anyName/except//anyName forbidden construct\n",
7293 NULL, NULL);
7294 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7295 xmlRngPErr(ctxt, cur,
7296 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7297 "Found nsName/except//anyName forbidden construct\n",
7298 NULL, NULL);
7299 }
7300 }
7301 /*
7302 * Thisd is not an else since "include" is transformed
7303 * into a div
7304 */
7305 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7306 xmlChar *ns;
7307 xmlNodePtr child, ins, tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007308
Daniel Veillard4c004142003-10-07 11:33:24 +00007309 /*
7310 * implements rule 4.11
7311 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00007312
Daniel Veillard4c004142003-10-07 11:33:24 +00007313 ns = xmlGetProp(cur, BAD_CAST "ns");
7314
7315 child = cur->children;
7316 ins = cur;
7317 while (child != NULL) {
7318 if (ns != NULL) {
7319 if (!xmlHasProp(child, BAD_CAST "ns")) {
7320 xmlSetProp(child, BAD_CAST "ns", ns);
7321 }
7322 }
7323 tmp = child->next;
7324 xmlUnlinkNode(child);
7325 ins = xmlAddNextSibling(ins, child);
7326 child = tmp;
7327 }
7328 if (ns != NULL)
7329 xmlFree(ns);
William M. Brack8eabb052004-06-07 14:15:54 +00007330 /*
7331 * Since we are about to delete cur, if it's nsDef is non-NULL we
7332 * need to preserve it (it contains the ns definitions for the
7333 * children we just moved). We'll just stick it on to the end
7334 * of cur->parent's list, since it's never going to be re-serialized
7335 * (bug 143738).
7336 */
7337 if (cur->nsDef != NULL) {
7338 xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
7339 while (parDef->next != NULL)
7340 parDef = parDef->next;
7341 parDef->next = cur->nsDef;
7342 cur->nsDef = NULL;
7343 }
Daniel Veillard4c004142003-10-07 11:33:24 +00007344 delete = cur;
7345 goto skip_children;
7346 }
7347 }
7348 }
7349 /*
7350 * Simplification 4.2 whitespaces
7351 */
7352 else if ((cur->type == XML_TEXT_NODE) ||
7353 (cur->type == XML_CDATA_SECTION_NODE)) {
7354 if (IS_BLANK_NODE(cur)) {
7355 if (cur->parent->type == XML_ELEMENT_NODE) {
7356 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7357 &&
7358 (!xmlStrEqual
7359 (cur->parent->name, BAD_CAST "param")))
7360 delete = cur;
7361 } else {
7362 delete = cur;
7363 goto skip_children;
7364 }
7365 }
7366 } else {
7367 delete = cur;
7368 goto skip_children;
7369 }
7370
7371 /*
7372 * Skip to next node
7373 */
7374 if (cur->children != NULL) {
7375 if ((cur->children->type != XML_ENTITY_DECL) &&
7376 (cur->children->type != XML_ENTITY_REF_NODE) &&
7377 (cur->children->type != XML_ENTITY_NODE)) {
7378 cur = cur->children;
7379 continue;
7380 }
7381 }
7382 skip_children:
7383 if (cur->next != NULL) {
7384 cur = cur->next;
7385 continue;
7386 }
7387
7388 do {
7389 cur = cur->parent;
7390 if (cur == NULL)
7391 break;
7392 if (cur == root) {
7393 cur = NULL;
7394 break;
7395 }
7396 if (cur->next != NULL) {
7397 cur = cur->next;
7398 break;
7399 }
7400 } while (cur != NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007401 }
7402 if (delete != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007403 xmlUnlinkNode(delete);
7404 xmlFreeNode(delete);
7405 delete = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007406 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00007407}
Daniel Veillard6eadf632003-01-23 18:29:16 +00007408
Daniel Veillardc5312d72003-02-21 17:14:10 +00007409/**
7410 * xmlRelaxNGCleanupDoc:
7411 * @ctxt: a Relax-NG parser context
7412 * @doc: an xmldocPtr document pointer
7413 *
7414 * Cleanup the document from unwanted nodes for parsing, resolve
7415 * Include and externalRef lookups.
7416 *
7417 * Returns the cleaned up document or NULL in case of error
7418 */
7419static xmlDocPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007420xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7421{
Daniel Veillardc5312d72003-02-21 17:14:10 +00007422 xmlNodePtr root;
7423
7424 /*
7425 * Extract the root
7426 */
7427 root = xmlDocGetRootElement(doc);
7428 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007429 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7430 ctxt->URL, NULL);
Daniel Veillardc5312d72003-02-21 17:14:10 +00007431 return (NULL);
7432 }
7433 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillard4c004142003-10-07 11:33:24 +00007434 return (doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007435}
7436
7437/**
7438 * xmlRelaxNGParse:
7439 * @ctxt: a Relax-NG parser context
7440 *
7441 * parse a schema definition resource and build an internal
7442 * XML Shema struture which can be used to validate instances.
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007443 *
7444 * Returns the internal XML RelaxNG structure built from the resource or
7445 * NULL in case of error
7446 */
7447xmlRelaxNGPtr
7448xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7449{
7450 xmlRelaxNGPtr ret = NULL;
7451 xmlDocPtr doc;
7452 xmlNodePtr root;
7453
7454 xmlRelaxNGInitTypes();
7455
7456 if (ctxt == NULL)
7457 return (NULL);
7458
7459 /*
7460 * First step is to parse the input document into an DOM/Infoset
7461 */
7462 if (ctxt->URL != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007463 doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007464 if (doc == NULL) {
7465 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7466 "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7467 NULL);
7468 return (NULL);
7469 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007470 } else if (ctxt->buffer != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007471 doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007472 if (doc == NULL) {
7473 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7474 "xmlRelaxNGParse: could not parse schemas\n", NULL,
7475 NULL);
7476 return (NULL);
7477 }
7478 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7479 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard33300b42003-04-17 09:09:19 +00007480 } else if (ctxt->document != NULL) {
7481 doc = ctxt->document;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007482 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007483 xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7484 "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7485 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007486 }
7487 ctxt->document = doc;
7488
7489 /*
7490 * Some preprocessing of the document content
7491 */
7492 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7493 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007494 xmlFreeDoc(ctxt->document);
7495 ctxt->document = NULL;
7496 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007497 }
7498
Daniel Veillard6eadf632003-01-23 18:29:16 +00007499 /*
7500 * Then do the parsing for good
7501 */
7502 root = xmlDocGetRootElement(doc);
7503 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007504 xmlRngPErr(ctxt, (xmlNodePtr) doc,
7505 XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
William M. Brack700f9872006-05-06 03:16:22 +00007506 (ctxt->URL ? ctxt->URL : BAD_CAST "schemas"), NULL);
Daniel Veillard3f845a92006-04-13 07:33:44 +00007507
7508 xmlFreeDoc(ctxt->document);
7509 ctxt->document = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007510 return (NULL);
7511 }
7512 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007513 if (ret == NULL) {
Daniel Veillard3f845a92006-04-13 07:33:44 +00007514 xmlFreeDoc(ctxt->document);
7515 ctxt->document = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007516 return (NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007517 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007518
7519 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007520 * Check the ref/defines links
7521 */
7522 /*
7523 * try to preprocess interleaves
7524 */
7525 if (ctxt->interleaves != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007526 xmlHashScan(ctxt->interleaves,
7527 (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007528 }
7529
7530 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007531 * if there was a parsing error return NULL
7532 */
7533 if (ctxt->nbErrors > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007534 xmlRelaxNGFree(ret);
7535 ctxt->document = NULL;
7536 xmlFreeDoc(doc);
7537 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007538 }
7539
7540 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007541 * try to compile (parts of) the schemas
7542 */
Daniel Veillardce192eb2003-04-16 15:58:05 +00007543 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7544 if (ret->topgrammar->start->type != XML_RELAXNG_START) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007545 xmlRelaxNGDefinePtr def;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007546
Daniel Veillard4c004142003-10-07 11:33:24 +00007547 def = xmlRelaxNGNewDefine(ctxt, NULL);
7548 if (def != NULL) {
7549 def->type = XML_RELAXNG_START;
7550 def->content = ret->topgrammar->start;
7551 ret->topgrammar->start = def;
7552 }
7553 }
7554 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007555 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007556
7557 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007558 * Transfer the pointer for cleanup at the schema level.
7559 */
7560 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007561 ctxt->document = NULL;
7562 ret->documents = ctxt->documents;
7563 ctxt->documents = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007564
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007565 ret->includes = ctxt->includes;
7566 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007567 ret->defNr = ctxt->defNr;
7568 ret->defTab = ctxt->defTab;
7569 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007570 if (ctxt->idref == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00007571 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007572
7573 return (ret);
7574}
Daniel Veillard4c004142003-10-07 11:33:24 +00007575
Daniel Veillard6eadf632003-01-23 18:29:16 +00007576/**
7577 * xmlRelaxNGSetParserErrors:
7578 * @ctxt: a Relax-NG validation context
7579 * @err: the error callback
7580 * @warn: the warning callback
7581 * @ctx: contextual data for the callbacks
7582 *
7583 * Set the callback functions used to handle errors for a validation context
7584 */
7585void
7586xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007587 xmlRelaxNGValidityErrorFunc err,
7588 xmlRelaxNGValidityWarningFunc warn, void *ctx)
7589{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007590 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007591 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007592 ctxt->error = err;
7593 ctxt->warning = warn;
Daniel Veillardb30ca312005-09-04 13:50:03 +00007594 ctxt->serror = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007595 ctxt->userData = ctx;
7596}
Daniel Veillard409a8142003-07-18 15:16:57 +00007597
7598/**
7599 * xmlRelaxNGGetParserErrors:
7600 * @ctxt: a Relax-NG validation context
7601 * @err: the error callback result
7602 * @warn: the warning callback result
7603 * @ctx: contextual data for the callbacks result
7604 *
7605 * Get the callback information used to handle errors for a validation context
7606 *
7607 * Returns -1 in case of failure, 0 otherwise.
7608 */
7609int
7610xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007611 xmlRelaxNGValidityErrorFunc * err,
7612 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
7613{
Daniel Veillard409a8142003-07-18 15:16:57 +00007614 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007615 return (-1);
7616 if (err != NULL)
7617 *err = ctxt->error;
7618 if (warn != NULL)
7619 *warn = ctxt->warning;
7620 if (ctx != NULL)
7621 *ctx = ctxt->userData;
7622 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +00007623}
7624
Daniel Veillardb2f8f1d2006-04-28 16:30:48 +00007625/**
7626 * xmlRelaxNGSetParserStructuredErrors:
7627 * @ctxt: a Relax-NG parser context
7628 * @serror: the error callback
7629 * @ctx: contextual data for the callbacks
7630 *
7631 * Set the callback functions used to handle errors for a parsing context
7632 */
Kasimier T. Buchcika930fbe2006-01-09 16:28:20 +00007633void
Daniel Veillardb2f8f1d2006-04-28 16:30:48 +00007634xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt,
Kasimier T. Buchcika930fbe2006-01-09 16:28:20 +00007635 xmlStructuredErrorFunc serror,
7636 void *ctx)
7637{
7638 if (ctxt == NULL)
7639 return;
7640 ctxt->serror = serror;
7641 ctxt->error = NULL;
7642 ctxt->warning = NULL;
7643 ctxt->userData = ctx;
7644}
7645
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007646#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard4c004142003-10-07 11:33:24 +00007647
Daniel Veillard6eadf632003-01-23 18:29:16 +00007648/************************************************************************
7649 * *
7650 * Dump back a compiled form *
7651 * *
7652 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007653static void xmlRelaxNGDumpDefine(FILE * output,
7654 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007655
7656/**
7657 * xmlRelaxNGDumpDefines:
7658 * @output: the file output
7659 * @defines: a list of define structures
7660 *
7661 * Dump a RelaxNG structure back
7662 */
7663static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007664xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
7665{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007666 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007667 xmlRelaxNGDumpDefine(output, defines);
7668 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007669 }
7670}
7671
7672/**
7673 * xmlRelaxNGDumpDefine:
7674 * @output: the file output
7675 * @define: a define structure
7676 *
7677 * Dump a RelaxNG structure back
7678 */
7679static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007680xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
7681{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007682 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007683 return;
7684 switch (define->type) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007685 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00007686 fprintf(output, "<empty/>\n");
7687 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007688 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00007689 fprintf(output, "<notAllowed/>\n");
7690 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007691 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007692 fprintf(output, "<text/>\n");
7693 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007694 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007695 fprintf(output, "<element>\n");
7696 if (define->name != NULL) {
7697 fprintf(output, "<name");
7698 if (define->ns != NULL)
7699 fprintf(output, " ns=\"%s\"", define->ns);
7700 fprintf(output, ">%s</name>\n", define->name);
7701 }
7702 xmlRelaxNGDumpDefines(output, define->attrs);
7703 xmlRelaxNGDumpDefines(output, define->content);
7704 fprintf(output, "</element>\n");
7705 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007706 case XML_RELAXNG_LIST:
Daniel Veillard4c004142003-10-07 11:33:24 +00007707 fprintf(output, "<list>\n");
7708 xmlRelaxNGDumpDefines(output, define->content);
7709 fprintf(output, "</list>\n");
7710 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007711 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007712 fprintf(output, "<oneOrMore>\n");
7713 xmlRelaxNGDumpDefines(output, define->content);
7714 fprintf(output, "</oneOrMore>\n");
7715 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007716 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007717 fprintf(output, "<zeroOrMore>\n");
7718 xmlRelaxNGDumpDefines(output, define->content);
7719 fprintf(output, "</zeroOrMore>\n");
7720 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007721 case XML_RELAXNG_CHOICE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007722 fprintf(output, "<choice>\n");
7723 xmlRelaxNGDumpDefines(output, define->content);
7724 fprintf(output, "</choice>\n");
7725 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007726 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00007727 fprintf(output, "<group>\n");
7728 xmlRelaxNGDumpDefines(output, define->content);
7729 fprintf(output, "</group>\n");
7730 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007731 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007732 fprintf(output, "<interleave>\n");
7733 xmlRelaxNGDumpDefines(output, define->content);
7734 fprintf(output, "</interleave>\n");
7735 break;
7736 case XML_RELAXNG_OPTIONAL:
7737 fprintf(output, "<optional>\n");
7738 xmlRelaxNGDumpDefines(output, define->content);
7739 fprintf(output, "</optional>\n");
7740 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007741 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007742 fprintf(output, "<attribute>\n");
7743 xmlRelaxNGDumpDefines(output, define->content);
7744 fprintf(output, "</attribute>\n");
7745 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007746 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007747 fprintf(output, "<define");
7748 if (define->name != NULL)
7749 fprintf(output, " name=\"%s\"", define->name);
7750 fprintf(output, ">\n");
7751 xmlRelaxNGDumpDefines(output, define->content);
7752 fprintf(output, "</define>\n");
7753 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007754 case XML_RELAXNG_REF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007755 fprintf(output, "<ref");
7756 if (define->name != NULL)
7757 fprintf(output, " name=\"%s\"", define->name);
7758 fprintf(output, ">\n");
7759 xmlRelaxNGDumpDefines(output, define->content);
7760 fprintf(output, "</ref>\n");
7761 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007762 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007763 fprintf(output, "<parentRef");
7764 if (define->name != NULL)
7765 fprintf(output, " name=\"%s\"", define->name);
7766 fprintf(output, ">\n");
7767 xmlRelaxNGDumpDefines(output, define->content);
7768 fprintf(output, "</parentRef>\n");
7769 break;
7770 case XML_RELAXNG_EXTERNALREF:
7771 fprintf(output, "<externalRef>");
7772 xmlRelaxNGDumpDefines(output, define->content);
7773 fprintf(output, "</externalRef>\n");
7774 break;
Daniel Veillarde431a272003-01-29 23:02:33 +00007775 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007776 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007777 TODO break;
7778 case XML_RELAXNG_START:
7779 case XML_RELAXNG_EXCEPT:
7780 case XML_RELAXNG_PARAM:
7781 TODO break;
7782 case XML_RELAXNG_NOOP:
7783 xmlRelaxNGDumpDefines(output, define->content);
7784 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007785 }
7786}
Daniel Veillard4c004142003-10-07 11:33:24 +00007787
Daniel Veillard6eadf632003-01-23 18:29:16 +00007788/**
7789 * xmlRelaxNGDumpGrammar:
7790 * @output: the file output
7791 * @grammar: a grammar structure
7792 * @top: is this a top grammar
7793 *
7794 * Dump a RelaxNG structure back
7795 */
7796static void
7797xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7798{
7799 if (grammar == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007800 return;
7801
Daniel Veillard6eadf632003-01-23 18:29:16 +00007802 fprintf(output, "<grammar");
7803 if (top)
Daniel Veillard4c004142003-10-07 11:33:24 +00007804 fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7805 switch (grammar->combine) {
7806 case XML_RELAXNG_COMBINE_UNDEFINED:
7807 break;
7808 case XML_RELAXNG_COMBINE_CHOICE:
7809 fprintf(output, " combine=\"choice\"");
7810 break;
7811 case XML_RELAXNG_COMBINE_INTERLEAVE:
7812 fprintf(output, " combine=\"interleave\"");
7813 break;
7814 default:
7815 fprintf(output, " <!-- invalid combine value -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007816 }
7817 fprintf(output, ">\n");
7818 if (grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007819 fprintf(output, " <!-- grammar had no start -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007820 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007821 fprintf(output, "<start>\n");
7822 xmlRelaxNGDumpDefine(output, grammar->start);
7823 fprintf(output, "</start>\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007824 }
7825 /* TODO ? Dump the defines ? */
7826 fprintf(output, "</grammar>\n");
7827}
7828
7829/**
7830 * xmlRelaxNGDump:
7831 * @output: the file output
7832 * @schema: a schema structure
7833 *
7834 * Dump a RelaxNG structure back
7835 */
7836void
7837xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7838{
Daniel Veillardce682bc2004-11-05 17:22:25 +00007839 if (output == NULL)
7840 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007841 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007842 fprintf(output, "RelaxNG empty or failed to compile\n");
7843 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007844 }
7845 fprintf(output, "RelaxNG: ");
7846 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007847 fprintf(output, "no document\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007848 } else if (schema->doc->URL != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007849 fprintf(output, "%s\n", schema->doc->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007850 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007851 fprintf(output, "\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007852 }
7853 if (schema->topgrammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007854 fprintf(output, "RelaxNG has no top grammar\n");
7855 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007856 }
7857 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7858}
7859
Daniel Veillardfebcca42003-02-16 15:44:18 +00007860/**
7861 * xmlRelaxNGDumpTree:
7862 * @output: the file output
7863 * @schema: a schema structure
7864 *
7865 * Dump the transformed RelaxNG tree.
7866 */
7867void
7868xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7869{
Daniel Veillardce682bc2004-11-05 17:22:25 +00007870 if (output == NULL)
7871 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007872 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007873 fprintf(output, "RelaxNG empty or failed to compile\n");
7874 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007875 }
7876 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007877 fprintf(output, "no document\n");
Daniel Veillardfebcca42003-02-16 15:44:18 +00007878 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007879 xmlDocDump(output, schema->doc);
Daniel Veillardfebcca42003-02-16 15:44:18 +00007880 }
7881}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007882#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardfebcca42003-02-16 15:44:18 +00007883
Daniel Veillard6eadf632003-01-23 18:29:16 +00007884/************************************************************************
7885 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007886 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007887 * *
7888 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007889static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7890 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007891
7892/**
7893 * xmlRelaxNGValidateCompiledCallback:
7894 * @exec: the regular expression instance
7895 * @token: the token which matched
7896 * @transdata: callback data, the define for the subelement if available
7897 @ @inputdata: callback data, the Relax NG validation context
7898 *
7899 * Handle the callback and if needed validate the element children.
7900 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007901static void
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007902xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00007903 const xmlChar * token,
7904 void *transdata, void *inputdata)
7905{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007906 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7907 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7908 int ret;
7909
7910#ifdef DEBUG_COMPILE
7911 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007912 "Compiled callback for: '%s'\n", token);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007913#endif
7914 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007915 fprintf(stderr, "callback on %s missing context\n", token);
Daniel Veillard4c004142003-10-07 11:33:24 +00007916 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007917 }
7918 if (define == NULL) {
7919 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007920 return;
7921 fprintf(stderr, "callback on %s missing define\n", token);
7922 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7923 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7924 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007925 }
7926 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007927 fprintf(stderr, "callback on %s missing info\n", token);
7928 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7929 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7930 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007931 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007932 fprintf(stderr, "callback on %s define is not element\n", token);
7933 if (ctxt->errNo == XML_RELAXNG_OK)
7934 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7935 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007936 }
7937 ret = xmlRelaxNGValidateDefinition(ctxt, define);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007938 if (ret != 0)
7939 ctxt->perr = ret;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007940}
7941
7942/**
7943 * xmlRelaxNGValidateCompiledContent:
7944 * @ctxt: the RelaxNG validation context
7945 * @regexp: the regular expression as compiled
7946 * @content: list of children to test against the regexp
7947 *
7948 * Validate the content model of an element or start using the regexp
7949 *
7950 * Returns 0 in case of success, -1 in case of error.
7951 */
7952static int
7953xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007954 xmlRegexpPtr regexp, xmlNodePtr content)
7955{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007956 xmlRegExecCtxtPtr exec;
7957 xmlNodePtr cur;
Daniel Veillard62163602003-04-17 09:36:38 +00007958 int ret = 0;
Daniel Veillard14b56432006-03-09 18:41:40 +00007959 int oldperr;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007960
7961 if ((ctxt == NULL) || (regexp == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00007962 return (-1);
Daniel Veillard14b56432006-03-09 18:41:40 +00007963 oldperr = ctxt->perr;
Daniel Veillard4c004142003-10-07 11:33:24 +00007964 exec = xmlRegNewExecCtxt(regexp,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007965 xmlRelaxNGValidateCompiledCallback, ctxt);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007966 ctxt->perr = 0;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007967 cur = content;
7968 while (cur != NULL) {
7969 ctxt->state->seq = cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00007970 switch (cur->type) {
7971 case XML_TEXT_NODE:
7972 case XML_CDATA_SECTION_NODE:
7973 if (xmlIsBlankNode(cur))
7974 break;
7975 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7976 if (ret < 0) {
7977 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
7978 cur->parent->name);
7979 }
7980 break;
7981 case XML_ELEMENT_NODE:
7982 if (cur->ns != NULL) {
7983 ret = xmlRegExecPushString2(exec, cur->name,
7984 cur->ns->href, ctxt);
7985 } else {
7986 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7987 }
7988 if (ret < 0) {
7989 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7990 }
7991 break;
7992 default:
7993 break;
7994 }
7995 if (ret < 0)
7996 break;
7997 /*
7998 * Switch to next element
7999 */
8000 cur = cur->next;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008001 }
8002 ret = xmlRegExecPushString(exec, NULL, NULL);
8003 if (ret == 1) {
8004 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00008005 ctxt->state->seq = NULL;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008006 } else if (ret == 0) {
8007 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008008 * TODO: get some of the names needed to exit the current state of exec
8009 */
8010 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8011 ret = -1;
8012 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8013 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008014 } else {
8015 ret = -1;
8016 }
8017 xmlRegFreeExecCtxt(exec);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00008018 /*
8019 * There might be content model errors outside of the pure
8020 * regexp validation, e.g. for attribute values.
8021 */
8022 if ((ret == 0) && (ctxt->perr != 0)) {
8023 ret = ctxt->perr;
8024 }
8025 ctxt->perr = oldperr;
Daniel Veillard4c004142003-10-07 11:33:24 +00008026 return (ret);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008027}
8028
8029/************************************************************************
8030 * *
8031 * Progressive validation of when possible *
8032 * *
8033 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00008034static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8035 xmlRelaxNGDefinePtr defines);
8036static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
William M. Brack272693c2003-11-14 16:20:34 +00008037 int dolog);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00008038static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008039
8040/**
8041 * xmlRelaxNGElemPush:
8042 * @ctxt: the validation context
8043 * @exec: the regexp runtime for the new content model
8044 *
8045 * Push a new regexp for the current node content model on the stack
8046 *
8047 * Returns 0 in case of success and -1 in case of error.
8048 */
8049static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008050xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
8051{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008052 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008053 ctxt->elemMax = 10;
8054 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
8055 sizeof
8056 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00008057 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008058 xmlRngVErrMemory(ctxt, "validating\n");
8059 return (-1);
8060 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00008061 }
8062 if (ctxt->elemNr >= ctxt->elemMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008063 ctxt->elemMax *= 2;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008064 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00008065 ctxt->elemMax *
8066 sizeof
8067 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00008068 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008069 xmlRngVErrMemory(ctxt, "validating\n");
8070 return (-1);
8071 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00008072 }
8073 ctxt->elemTab[ctxt->elemNr++] = exec;
8074 ctxt->elem = exec;
Daniel Veillard4c004142003-10-07 11:33:24 +00008075 return (0);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008076}
8077
8078/**
8079 * xmlRelaxNGElemPop:
8080 * @ctxt: the validation context
8081 *
8082 * Pop the regexp of the current node content model from the stack
8083 *
8084 * Returns the exec or NULL if empty
8085 */
8086static xmlRegExecCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00008087xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
8088{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008089 xmlRegExecCtxtPtr ret;
8090
Daniel Veillard4c004142003-10-07 11:33:24 +00008091 if (ctxt->elemNr <= 0)
8092 return (NULL);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008093 ctxt->elemNr--;
8094 ret = ctxt->elemTab[ctxt->elemNr];
8095 ctxt->elemTab[ctxt->elemNr] = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00008096 if (ctxt->elemNr > 0)
Daniel Veillardf4e55762003-04-15 23:32:22 +00008097 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
8098 else
Daniel Veillard4c004142003-10-07 11:33:24 +00008099 ctxt->elem = NULL;
8100 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008101}
8102
8103/**
8104 * xmlRelaxNGValidateProgressiveCallback:
8105 * @exec: the regular expression instance
8106 * @token: the token which matched
8107 * @transdata: callback data, the define for the subelement if available
8108 @ @inputdata: callback data, the Relax NG validation context
8109 *
8110 * Handle the callback and if needed validate the element children.
8111 * some of the in/out informations are passed via the context in @inputdata.
8112 */
Daniel Veillard4c004142003-10-07 11:33:24 +00008113static void
8114xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
8115 ATTRIBUTE_UNUSED,
8116 const xmlChar * token,
8117 void *transdata, void *inputdata)
8118{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008119 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
8120 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008121 xmlRelaxNGValidStatePtr state, oldstate;
Daniel Veillard14b56432006-03-09 18:41:40 +00008122 xmlNodePtr node;
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00008123 int ret = 0, oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008124
8125#ifdef DEBUG_PROGRESSIVE
8126 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00008127 "Progressive callback for: '%s'\n", token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008128#endif
8129 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008130 fprintf(stderr, "callback on %s missing context\n", token);
8131 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008132 }
Daniel Veillard14b56432006-03-09 18:41:40 +00008133 node = ctxt->pnode;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008134 ctxt->pstate = 1;
8135 if (define == NULL) {
8136 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00008137 return;
8138 fprintf(stderr, "callback on %s missing define\n", token);
8139 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8140 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8141 ctxt->pstate = -1;
8142 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008143 }
8144 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008145 fprintf(stderr, "callback on %s missing info\n", token);
8146 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8147 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8148 ctxt->pstate = -1;
8149 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008150 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008151 fprintf(stderr, "callback on %s define is not element\n", token);
8152 if (ctxt->errNo == XML_RELAXNG_OK)
8153 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8154 ctxt->pstate = -1;
8155 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008156 }
8157 if (node->type != XML_ELEMENT_NODE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008158 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8159 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8160 xmlRelaxNGDumpValidError(ctxt);
8161 ctxt->pstate = -1;
8162 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008163 }
8164 if (define->contModel == NULL) {
8165 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008166 * this node cannot be validated in a streamable fashion
8167 */
Daniel Veillardf4e55762003-04-15 23:32:22 +00008168#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008169 xmlGenericError(xmlGenericErrorContext,
8170 "Element '%s' validation is not streamable\n",
8171 token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008172#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008173 ctxt->pstate = 0;
8174 ctxt->pdef = define;
8175 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008176 }
8177 exec = xmlRegNewExecCtxt(define->contModel,
Daniel Veillard4c004142003-10-07 11:33:24 +00008178 xmlRelaxNGValidateProgressiveCallback, ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008179 if (exec == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008180 ctxt->pstate = -1;
8181 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008182 }
8183 xmlRelaxNGElemPush(ctxt, exec);
8184
8185 /*
8186 * Validate the attributes part of the content.
8187 */
8188 state = xmlRelaxNGNewValidState(ctxt, node);
8189 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008190 ctxt->pstate = -1;
8191 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008192 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008193 oldstate = ctxt->state;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008194 ctxt->state = state;
8195 if (define->attrs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008196 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8197 if (ret != 0) {
8198 ctxt->pstate = -1;
8199 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8200 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00008201 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008202 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008203 ctxt->state->seq = NULL;
8204 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
8205 if (ret != 0) {
8206 ctxt->pstate = -1;
8207 }
8208 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008209 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008210 int tmp = -1, i;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008211
8212 oldflags = ctxt->flags;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008213
Daniel Veillard4c004142003-10-07 11:33:24 +00008214 for (i = 0; i < ctxt->states->nbState; i++) {
8215 state = ctxt->states->tabState[i];
8216 ctxt->state = state;
8217 ctxt->state->seq = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008218
Daniel Veillard4c004142003-10-07 11:33:24 +00008219 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
8220 tmp = 0;
8221 break;
8222 }
8223 }
8224 if (tmp != 0) {
8225 /*
8226 * validation error, log the message for the "best" one
8227 */
8228 ctxt->flags |= FLAGS_IGNORABLE;
8229 xmlRelaxNGLogBestError(ctxt);
8230 }
8231 for (i = 0; i < ctxt->states->nbState; i++) {
8232 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
8233 }
8234 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8235 ctxt->states = NULL;
8236 if ((ret == 0) && (tmp == -1))
8237 ctxt->pstate = -1;
8238 ctxt->flags = oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008239 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008240 if (ctxt->pstate == -1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008241 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8242 xmlRelaxNGDumpValidError(ctxt);
8243 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008244 }
8245 ctxt->state = oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008246}
8247
8248/**
8249 * xmlRelaxNGValidatePushElement:
8250 * @ctxt: the validation context
8251 * @doc: a document instance
8252 * @elem: an element instance
8253 *
8254 * Push a new element start on the RelaxNG validation stack.
8255 *
8256 * returns 1 if no validation problem was found or 0 if validating the
8257 * element requires a full node, and -1 in case of error.
8258 */
8259int
Daniel Veillard33300b42003-04-17 09:09:19 +00008260xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
8261 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00008262 xmlNodePtr elem)
8263{
8264 int ret = 1;
8265
8266 if ((ctxt == NULL) || (elem == NULL))
8267 return (-1);
8268
8269#ifdef DEBUG_PROGRESSIVE
8270 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
8271#endif
8272 if (ctxt->elem == 0) {
8273 xmlRelaxNGPtr schema;
8274 xmlRelaxNGGrammarPtr grammar;
8275 xmlRegExecCtxtPtr exec;
8276 xmlRelaxNGDefinePtr define;
8277
8278 schema = ctxt->schema;
8279 if (schema == NULL) {
8280 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8281 return (-1);
8282 }
8283 grammar = schema->topgrammar;
8284 if ((grammar == NULL) || (grammar->start == NULL)) {
8285 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8286 return (-1);
8287 }
8288 define = grammar->start;
8289 if (define->contModel == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008290 ctxt->pdef = define;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008291 return (0);
8292 }
8293 exec = xmlRegNewExecCtxt(define->contModel,
8294 xmlRelaxNGValidateProgressiveCallback,
8295 ctxt);
8296 if (exec == NULL) {
8297 return (-1);
8298 }
8299 xmlRelaxNGElemPush(ctxt, exec);
8300 }
8301 ctxt->pnode = elem;
8302 ctxt->pstate = 0;
8303 if (elem->ns != NULL) {
8304 ret =
8305 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8306 ctxt);
8307 } else {
8308 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8309 }
8310 if (ret < 0) {
8311 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8312 } else {
8313 if (ctxt->pstate == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008314 ret = 0;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008315 else if (ctxt->pstate < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008316 ret = -1;
8317 else
8318 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008319 }
8320#ifdef DEBUG_PROGRESSIVE
8321 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008322 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8323 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008324#endif
8325 return (ret);
8326}
8327
8328/**
8329 * xmlRelaxNGValidatePushCData:
8330 * @ctxt: the RelaxNG validation context
8331 * @data: some character data read
8332 * @len: the lenght of the data
8333 *
8334 * check the CData parsed for validation in the current stack
8335 *
8336 * returns 1 if no validation problem was found or -1 otherwise
8337 */
8338int
8339xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00008340 const xmlChar * data, int len ATTRIBUTE_UNUSED)
Daniel Veillardf4e55762003-04-15 23:32:22 +00008341{
8342 int ret = 1;
8343
8344 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8345 return (-1);
8346
8347#ifdef DEBUG_PROGRESSIVE
8348 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8349#endif
8350
8351 while (*data != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008352 if (!IS_BLANK_CH(*data))
Daniel Veillardf4e55762003-04-15 23:32:22 +00008353 break;
8354 data++;
8355 }
8356 if (*data == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008357 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008358
8359 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8360 if (ret < 0) {
Daniel Veillard33300b42003-04-17 09:09:19 +00008361 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008362#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008363 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008364#endif
8365
Daniel Veillard4c004142003-10-07 11:33:24 +00008366 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008367 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008368 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008369}
8370
8371/**
8372 * xmlRelaxNGValidatePopElement:
8373 * @ctxt: the RelaxNG validation context
8374 * @doc: a document instance
8375 * @elem: an element instance
8376 *
8377 * Pop the element end from the RelaxNG validation stack.
8378 *
8379 * returns 1 if no validation problem was found or 0 otherwise
8380 */
8381int
8382xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8383 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008384 xmlNodePtr elem)
8385{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008386 int ret;
8387 xmlRegExecCtxtPtr exec;
8388
Daniel Veillard4c004142003-10-07 11:33:24 +00008389 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
8390 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008391#ifdef DEBUG_PROGRESSIVE
8392 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8393#endif
8394 /*
8395 * verify that we reached a terminal state of the content model.
8396 */
8397 exec = xmlRelaxNGElemPop(ctxt);
8398 ret = xmlRegExecPushString(exec, NULL, NULL);
8399 if (ret == 0) {
8400 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008401 * TODO: get some of the names needed to exit the current state of exec
8402 */
8403 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8404 ret = -1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008405 } else if (ret < 0) {
8406 ret = -1;
8407 } else {
8408 ret = 1;
8409 }
8410 xmlRegFreeExecCtxt(exec);
8411#ifdef DEBUG_PROGRESSIVE
8412 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008413 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8414 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008415#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008416 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008417}
8418
8419/**
8420 * xmlRelaxNGValidateFullElement:
8421 * @ctxt: the validation context
8422 * @doc: a document instance
8423 * @elem: an element instance
8424 *
8425 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8426 * 0 and the content of the node has been expanded.
8427 *
8428 * returns 1 if no validation problem was found or -1 in case of error.
8429 */
8430int
Daniel Veillard33300b42003-04-17 09:09:19 +00008431xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8432 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008433 xmlNodePtr elem)
8434{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008435 int ret;
8436 xmlRelaxNGValidStatePtr state;
8437
Daniel Veillard4c004142003-10-07 11:33:24 +00008438 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
8439 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008440#ifdef DEBUG_PROGRESSIVE
8441 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8442#endif
8443 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8444 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008445 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008446 }
8447 state->seq = elem;
8448 ctxt->state = state;
8449 ctxt->errNo = XML_RELAXNG_OK;
8450 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
Daniel Veillard4c004142003-10-07 11:33:24 +00008451 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
8452 ret = -1;
8453 else
8454 ret = 1;
Daniel Veillard9fcd4622009-08-14 16:16:31 +02008455 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008456 ctxt->state = NULL;
8457#ifdef DEBUG_PROGRESSIVE
8458 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008459 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8460 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008461#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008462 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008463}
8464
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008465/************************************************************************
8466 * *
8467 * Generic interpreted validation implementation *
8468 * *
8469 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00008470static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8471 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008472
8473/**
8474 * xmlRelaxNGSkipIgnored:
8475 * @ctxt: a schema validation context
8476 * @node: the top node.
8477 *
8478 * Skip ignorable nodes in that context
8479 *
8480 * Returns the new sibling or NULL in case of error.
8481 */
8482static xmlNodePtr
8483xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008484 xmlNodePtr node)
8485{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008486 /*
8487 * TODO complete and handle entities
8488 */
8489 while ((node != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00008490 ((node->type == XML_COMMENT_NODE) ||
8491 (node->type == XML_PI_NODE) ||
William M. Brack7217c862004-03-15 02:43:56 +00008492 (node->type == XML_XINCLUDE_START) ||
8493 (node->type == XML_XINCLUDE_END) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00008494 (((node->type == XML_TEXT_NODE) ||
8495 (node->type == XML_CDATA_SECTION_NODE)) &&
8496 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8497 (IS_BLANK_NODE(node)))))) {
8498 node = node->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008499 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008500 return (node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008501}
8502
8503/**
Daniel Veillardedc91922003-01-26 00:52:04 +00008504 * xmlRelaxNGNormalize:
8505 * @ctxt: a schema validation context
8506 * @str: the string to normalize
8507 *
8508 * Implements the normalizeWhiteSpace( s ) function from
8509 * section 6.2.9 of the spec
8510 *
8511 * Returns the new string or NULL in case of error.
8512 */
8513static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00008514xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
8515{
Daniel Veillardedc91922003-01-26 00:52:04 +00008516 xmlChar *ret, *p;
8517 const xmlChar *tmp;
8518 int len;
Daniel Veillard4c004142003-10-07 11:33:24 +00008519
Daniel Veillardedc91922003-01-26 00:52:04 +00008520 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008521 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008522 tmp = str;
Daniel Veillard4c004142003-10-07 11:33:24 +00008523 while (*tmp != 0)
8524 tmp++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008525 len = tmp - str;
8526
Daniel Veillard3c908dc2003-04-19 00:07:51 +00008527 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
Daniel Veillardedc91922003-01-26 00:52:04 +00008528 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008529 xmlRngVErrMemory(ctxt, "validating\n");
8530 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008531 }
8532 p = ret;
William M. Brack76e95df2003-10-18 16:20:14 +00008533 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008534 str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008535 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008536 if (IS_BLANK_CH(*str)) {
8537 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008538 str++;
8539 if (*str == 0)
8540 break;
8541 *p++ = ' ';
8542 } else
8543 *p++ = *str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008544 }
8545 *p = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00008546 return (ret);
Daniel Veillardedc91922003-01-26 00:52:04 +00008547}
8548
8549/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008550 * xmlRelaxNGValidateDatatype:
8551 * @ctxt: a Relax-NG validation context
8552 * @value: the string value
8553 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008554 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008555 *
8556 * Validate the given value against the dataype
8557 *
8558 * Returns 0 if the validation succeeded or an error code.
8559 */
8560static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008561xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
8562 const xmlChar * value,
8563 xmlRelaxNGDefinePtr define, xmlNodePtr node)
8564{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008565 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008566 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008567 void *result = NULL;
8568 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008569
8570 if ((define == NULL) || (define->data == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008571 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008572 }
8573 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008574 if (lib->check != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008575 if ((define->attrs != NULL) &&
8576 (define->attrs->type == XML_RELAXNG_PARAM)) {
8577 ret =
8578 lib->check(lib->data, define->name, value, &result, node);
8579 } else {
8580 ret = lib->check(lib->data, define->name, value, NULL, node);
8581 }
8582 } else
8583 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008584 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008585 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8586 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8587 lib->freef(lib->data, result);
8588 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008589 } else if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008590 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008591 } else if (ret == 2) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008592 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008593 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008594 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8595 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008596 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008597 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008598 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008599 if (lib->facet != NULL) {
8600 tmp = lib->facet(lib->data, define->name, cur->name,
8601 cur->value, value, result);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008602 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008603 ret = -1;
8604 }
8605 cur = cur->next;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008606 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008607 if ((ret == 0) && (define->content != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008608 const xmlChar *oldvalue, *oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008609
Daniel Veillard4c004142003-10-07 11:33:24 +00008610 oldvalue = ctxt->state->value;
8611 oldendvalue = ctxt->state->endvalue;
8612 ctxt->state->value = (xmlChar *) value;
8613 ctxt->state->endvalue = NULL;
8614 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8615 ctxt->state->value = (xmlChar *) oldvalue;
8616 ctxt->state->endvalue = (xmlChar *) oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008617 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008618 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00008619 lib->freef(lib->data, result);
8620 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008621}
8622
8623/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008624 * xmlRelaxNGNextValue:
8625 * @ctxt: a Relax-NG validation context
8626 *
8627 * Skip to the next value when validating within a list
8628 *
8629 * Returns 0 if the operation succeeded or an error code.
8630 */
8631static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008632xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
8633{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008634 xmlChar *cur;
8635
8636 cur = ctxt->state->value;
8637 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008638 ctxt->state->value = NULL;
8639 ctxt->state->endvalue = NULL;
8640 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008641 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008642 while (*cur != 0)
8643 cur++;
8644 while ((cur != ctxt->state->endvalue) && (*cur == 0))
8645 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008646 if (cur == ctxt->state->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00008647 ctxt->state->value = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008648 else
Daniel Veillard4c004142003-10-07 11:33:24 +00008649 ctxt->state->value = cur;
8650 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008651}
8652
8653/**
8654 * xmlRelaxNGValidateValueList:
8655 * @ctxt: a Relax-NG validation context
8656 * @defines: the list of definitions to verify
8657 *
8658 * Validate the given set of definitions for the current value
8659 *
8660 * Returns 0 if the validation succeeded or an error code.
8661 */
8662static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008663xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8664 xmlRelaxNGDefinePtr defines)
8665{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008666 int ret = 0;
8667
8668 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008669 ret = xmlRelaxNGValidateValue(ctxt, defines);
8670 if (ret != 0)
8671 break;
8672 defines = defines->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008673 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008674 return (ret);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008675}
8676
8677/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008678 * xmlRelaxNGValidateValue:
8679 * @ctxt: a Relax-NG validation context
8680 * @define: the definition to verify
8681 *
8682 * Validate the given definition for the current value
8683 *
8684 * Returns 0 if the validation succeeded or an error code.
8685 */
8686static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008687xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8688 xmlRelaxNGDefinePtr define)
8689{
Daniel Veillardedc91922003-01-26 00:52:04 +00008690 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008691 xmlChar *value;
8692
8693 value = ctxt->state->value;
8694 switch (define->type) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008695 case XML_RELAXNG_EMPTY:{
8696 if ((value != NULL) && (value[0] != 0)) {
8697 int idx = 0;
Daniel Veillardd4310742003-02-18 21:12:46 +00008698
William M. Brack76e95df2003-10-18 16:20:14 +00008699 while (IS_BLANK_CH(value[idx]))
Daniel Veillard4c004142003-10-07 11:33:24 +00008700 idx++;
8701 if (value[idx] != 0)
8702 ret = -1;
8703 }
8704 break;
8705 }
8706 case XML_RELAXNG_TEXT:
8707 break;
8708 case XML_RELAXNG_VALUE:{
8709 if (!xmlStrEqual(value, define->value)) {
8710 if (define->name != NULL) {
8711 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillardedc91922003-01-26 00:52:04 +00008712
Daniel Veillard4c004142003-10-07 11:33:24 +00008713 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8714 if ((lib != NULL) && (lib->comp != NULL)) {
8715 ret = lib->comp(lib->data, define->name,
8716 define->value, define->node,
8717 (void *) define->attrs,
8718 value, ctxt->state->node);
8719 } else
8720 ret = -1;
8721 if (ret < 0) {
8722 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
8723 define->name);
8724 return (-1);
8725 } else if (ret == 1) {
8726 ret = 0;
8727 } else {
8728 ret = -1;
8729 }
8730 } else {
8731 xmlChar *nval, *nvalue;
Daniel Veillardedc91922003-01-26 00:52:04 +00008732
Daniel Veillard4c004142003-10-07 11:33:24 +00008733 /*
8734 * TODO: trivial optimizations are possible by
8735 * computing at compile-time
8736 */
8737 nval = xmlRelaxNGNormalize(ctxt, define->value);
8738 nvalue = xmlRelaxNGNormalize(ctxt, value);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008739
Daniel Veillard4c004142003-10-07 11:33:24 +00008740 if ((nval == NULL) || (nvalue == NULL) ||
8741 (!xmlStrEqual(nval, nvalue)))
8742 ret = -1;
8743 if (nval != NULL)
8744 xmlFree(nval);
8745 if (nvalue != NULL)
8746 xmlFree(nvalue);
8747 }
8748 }
8749 if (ret == 0)
8750 xmlRelaxNGNextValue(ctxt);
8751 break;
8752 }
8753 case XML_RELAXNG_DATATYPE:{
8754 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8755 ctxt->state->seq);
8756 if (ret == 0)
8757 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008758
Daniel Veillard4c004142003-10-07 11:33:24 +00008759 break;
8760 }
8761 case XML_RELAXNG_CHOICE:{
8762 xmlRelaxNGDefinePtr list = define->content;
8763 xmlChar *oldvalue;
8764
8765 oldflags = ctxt->flags;
8766 ctxt->flags |= FLAGS_IGNORABLE;
8767
8768 oldvalue = ctxt->state->value;
8769 while (list != NULL) {
8770 ret = xmlRelaxNGValidateValue(ctxt, list);
8771 if (ret == 0) {
8772 break;
8773 }
8774 ctxt->state->value = oldvalue;
8775 list = list->next;
8776 }
8777 ctxt->flags = oldflags;
8778 if (ret != 0) {
8779 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8780 xmlRelaxNGDumpValidError(ctxt);
8781 } else {
8782 if (ctxt->errNr > 0)
8783 xmlRelaxNGPopErrors(ctxt, 0);
8784 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008785 break;
8786 }
8787 case XML_RELAXNG_LIST:{
8788 xmlRelaxNGDefinePtr list = define->content;
8789 xmlChar *oldvalue, *oldend, *val, *cur;
8790
Daniel Veillard416589a2003-02-17 17:25:42 +00008791#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008792 int nb_values = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008793#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008794
Daniel Veillard4c004142003-10-07 11:33:24 +00008795 oldvalue = ctxt->state->value;
8796 oldend = ctxt->state->endvalue;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008797
Daniel Veillard4c004142003-10-07 11:33:24 +00008798 val = xmlStrdup(oldvalue);
8799 if (val == NULL) {
8800 val = xmlStrdup(BAD_CAST "");
8801 }
8802 if (val == NULL) {
8803 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8804 return (-1);
8805 }
8806 cur = val;
8807 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008808 if (IS_BLANK_CH(*cur)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008809 *cur = 0;
8810 cur++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008811#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008812 nb_values++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008813#endif
William M. Brack76e95df2003-10-18 16:20:14 +00008814 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00008815 *cur++ = 0;
8816 } else
8817 cur++;
8818 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008819#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008820 xmlGenericError(xmlGenericErrorContext,
8821 "list value: '%s' found %d items\n",
8822 oldvalue, nb_values);
8823 nb_values = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008824#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008825 ctxt->state->endvalue = cur;
8826 cur = val;
8827 while ((*cur == 0) && (cur != ctxt->state->endvalue))
8828 cur++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008829
Daniel Veillard4c004142003-10-07 11:33:24 +00008830 ctxt->state->value = cur;
8831
8832 while (list != NULL) {
8833 if (ctxt->state->value == ctxt->state->endvalue)
8834 ctxt->state->value = NULL;
8835 ret = xmlRelaxNGValidateValue(ctxt, list);
8836 if (ret != 0) {
8837#ifdef DEBUG_LIST
8838 xmlGenericError(xmlGenericErrorContext,
8839 "Failed to validate value: '%s' with %d rule\n",
8840 ctxt->state->value, nb_values);
8841#endif
8842 break;
8843 }
8844#ifdef DEBUG_LIST
8845 nb_values++;
8846#endif
8847 list = list->next;
8848 }
8849
8850 if ((ret == 0) && (ctxt->state->value != NULL) &&
8851 (ctxt->state->value != ctxt->state->endvalue)) {
8852 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
8853 ctxt->state->value);
8854 ret = -1;
8855 }
8856 xmlFree(val);
8857 ctxt->state->value = oldvalue;
8858 ctxt->state->endvalue = oldend;
8859 break;
8860 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008861 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00008862 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8863 if (ret != 0) {
8864 break;
8865 }
8866 /* no break on purpose */
8867 case XML_RELAXNG_ZEROORMORE:{
8868 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008869
Daniel Veillard4c004142003-10-07 11:33:24 +00008870 oldflags = ctxt->flags;
8871 ctxt->flags |= FLAGS_IGNORABLE;
8872 cur = ctxt->state->value;
8873 temp = NULL;
8874 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8875 (temp != cur)) {
8876 temp = cur;
8877 ret =
8878 xmlRelaxNGValidateValueList(ctxt, define->content);
8879 if (ret != 0) {
8880 ctxt->state->value = temp;
8881 ret = 0;
8882 break;
8883 }
8884 cur = ctxt->state->value;
8885 }
8886 ctxt->flags = oldflags;
Daniel Veillard14b56432006-03-09 18:41:40 +00008887 if (ctxt->errNr > 0)
8888 xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard4c004142003-10-07 11:33:24 +00008889 break;
8890 }
8891 case XML_RELAXNG_EXCEPT:{
8892 xmlRelaxNGDefinePtr list;
Daniel Veillard416589a2003-02-17 17:25:42 +00008893
Daniel Veillard4c004142003-10-07 11:33:24 +00008894 list = define->content;
8895 while (list != NULL) {
8896 ret = xmlRelaxNGValidateValue(ctxt, list);
8897 if (ret == 0) {
8898 ret = -1;
8899 break;
8900 } else
8901 ret = 0;
8902 list = list->next;
8903 }
8904 break;
8905 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008906 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008907 case XML_RELAXNG_GROUP:{
8908 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008909
Daniel Veillard4c004142003-10-07 11:33:24 +00008910 list = define->content;
8911 while (list != NULL) {
8912 ret = xmlRelaxNGValidateValue(ctxt, list);
8913 if (ret != 0) {
8914 ret = -1;
8915 break;
8916 } else
8917 ret = 0;
8918 list = list->next;
8919 }
8920 break;
8921 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008922 case XML_RELAXNG_REF:
8923 case XML_RELAXNG_PARENTREF:
Daniel Veillard25a1ce92008-06-02 16:04:12 +00008924 if (define->content == NULL) {
Daniel Veillard81c51e12009-08-14 18:52:10 +02008925 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
8926 ret = -1;
8927 } else {
8928 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8929 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008930 break;
8931 default:
8932 TODO ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008933 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008934 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008935}
8936
8937/**
8938 * xmlRelaxNGValidateValueContent:
8939 * @ctxt: a Relax-NG validation context
8940 * @defines: the list of definitions to verify
8941 *
8942 * Validate the given definitions for the current value
8943 *
8944 * Returns 0 if the validation succeeded or an error code.
8945 */
8946static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008947xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8948 xmlRelaxNGDefinePtr defines)
8949{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008950 int ret = 0;
8951
8952 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008953 ret = xmlRelaxNGValidateValue(ctxt, defines);
8954 if (ret != 0)
8955 break;
8956 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008957 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008958 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008959}
8960
8961/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008962 * xmlRelaxNGAttributeMatch:
8963 * @ctxt: a Relax-NG validation context
8964 * @define: the definition to check
8965 * @prop: the attribute
8966 *
8967 * Check if the attribute matches the definition nameClass
8968 *
8969 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8970 */
8971static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008972xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8973 xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
8974{
Daniel Veillardfd573f12003-03-16 17:52:32 +00008975 int ret;
8976
8977 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008978 if (!xmlStrEqual(define->name, prop->name))
8979 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008980 }
8981 if (define->ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008982 if (define->ns[0] == 0) {
8983 if (prop->ns != NULL)
8984 return (0);
8985 } else {
8986 if ((prop->ns == NULL) ||
8987 (!xmlStrEqual(define->ns, prop->ns->href)))
8988 return (0);
8989 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008990 }
8991 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008992 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008993 define = define->nameClass;
8994 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008995 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008996
Daniel Veillard4c004142003-10-07 11:33:24 +00008997 list = define->content;
8998 while (list != NULL) {
8999 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
9000 if (ret == 1)
9001 return (0);
9002 if (ret < 0)
9003 return (ret);
9004 list = list->next;
9005 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009006 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009007 TODO}
9008 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009009}
9010
9011/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00009012 * xmlRelaxNGValidateAttribute:
9013 * @ctxt: a Relax-NG validation context
9014 * @define: the definition to verify
9015 *
9016 * Validate the given attribute definition for that node
9017 *
9018 * Returns 0 if the validation succeeded or an error code.
9019 */
9020static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009021xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
9022 xmlRelaxNGDefinePtr define)
9023{
Daniel Veillard6eadf632003-01-23 18:29:16 +00009024 int ret = 0, i;
9025 xmlChar *value, *oldvalue;
9026 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00009027 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009028
Daniel Veillard1ed7f362003-02-03 10:57:45 +00009029 if (ctxt->state->nbAttrLeft <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00009030 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009031 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009032 for (i = 0; i < ctxt->state->nbAttrs; i++) {
9033 tmp = ctxt->state->attrs[i];
9034 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
9035 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
9036 (tmp->ns == NULL)) ||
9037 ((tmp->ns != NULL) &&
9038 (xmlStrEqual(define->ns, tmp->ns->href)))) {
9039 prop = tmp;
9040 break;
9041 }
9042 }
9043 }
9044 if (prop != NULL) {
9045 value = xmlNodeListGetString(prop->doc, prop->children, 1);
9046 oldvalue = ctxt->state->value;
9047 oldseq = ctxt->state->seq;
9048 ctxt->state->seq = (xmlNodePtr) prop;
9049 ctxt->state->value = value;
9050 ctxt->state->endvalue = NULL;
9051 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
9052 if (ctxt->state->value != NULL)
9053 value = ctxt->state->value;
9054 if (value != NULL)
9055 xmlFree(value);
9056 ctxt->state->value = oldvalue;
9057 ctxt->state->seq = oldseq;
9058 if (ret == 0) {
9059 /*
9060 * flag the attribute as processed
9061 */
9062 ctxt->state->attrs[i] = NULL;
9063 ctxt->state->nbAttrLeft--;
9064 }
9065 } else {
9066 ret = -1;
9067 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009068#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00009069 xmlGenericError(xmlGenericErrorContext,
9070 "xmlRelaxNGValidateAttribute(%s): %d\n",
9071 define->name, ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009072#endif
9073 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009074 for (i = 0; i < ctxt->state->nbAttrs; i++) {
9075 tmp = ctxt->state->attrs[i];
9076 if ((tmp != NULL) &&
9077 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
9078 prop = tmp;
9079 break;
9080 }
9081 }
9082 if (prop != NULL) {
9083 value = xmlNodeListGetString(prop->doc, prop->children, 1);
9084 oldvalue = ctxt->state->value;
9085 oldseq = ctxt->state->seq;
9086 ctxt->state->seq = (xmlNodePtr) prop;
9087 ctxt->state->value = value;
9088 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
9089 if (ctxt->state->value != NULL)
9090 value = ctxt->state->value;
9091 if (value != NULL)
9092 xmlFree(value);
9093 ctxt->state->value = oldvalue;
9094 ctxt->state->seq = oldseq;
9095 if (ret == 0) {
9096 /*
9097 * flag the attribute as processed
9098 */
9099 ctxt->state->attrs[i] = NULL;
9100 ctxt->state->nbAttrLeft--;
9101 }
9102 } else {
9103 ret = -1;
9104 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00009105#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00009106 if (define->ns != NULL) {
9107 xmlGenericError(xmlGenericErrorContext,
9108 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
9109 define->ns, ret);
9110 } else {
9111 xmlGenericError(xmlGenericErrorContext,
9112 "xmlRelaxNGValidateAttribute(anyName): %d\n",
9113 ret);
9114 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00009115#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00009116 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009117
9118 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009119}
9120
9121/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009122 * xmlRelaxNGValidateAttributeList:
9123 * @ctxt: a Relax-NG validation context
9124 * @define: the list of definition to verify
9125 *
9126 * Validate the given node against the list of attribute definitions
9127 *
9128 * Returns 0 if the validation succeeded or an error code.
9129 */
9130static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009131xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
9132 xmlRelaxNGDefinePtr defines)
9133{
Daniel Veillardce192eb2003-04-16 15:58:05 +00009134 int ret = 0, res;
9135 int needmore = 0;
9136 xmlRelaxNGDefinePtr cur;
9137
9138 cur = defines;
9139 while (cur != NULL) {
9140 if (cur->type == XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009141 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
9142 ret = -1;
9143 } else
9144 needmore = 1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009145 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009146 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00009147 if (!needmore)
Daniel Veillard4c004142003-10-07 11:33:24 +00009148 return (ret);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009149 cur = defines;
9150 while (cur != NULL) {
9151 if (cur->type != XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009152 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9153 res = xmlRelaxNGValidateDefinition(ctxt, cur);
9154 if (res < 0)
9155 ret = -1;
9156 } else {
9157 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9158 return (-1);
9159 }
9160 if (res == -1) /* continues on -2 */
9161 break;
9162 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00009163 cur = cur->next;
9164 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009165
9166 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009167}
9168
9169/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009170 * xmlRelaxNGNodeMatchesList:
9171 * @node: the node
9172 * @list: a NULL terminated array of definitions
9173 *
9174 * Check if a node can be matched by one of the definitions
9175 *
9176 * Returns 1 if matches 0 otherwise
9177 */
9178static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009179xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
9180{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009181 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009182 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009183
9184 if ((node == NULL) || (list == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00009185 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009186
9187 cur = list[i++];
9188 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009189 if ((node->type == XML_ELEMENT_NODE) &&
9190 (cur->type == XML_RELAXNG_ELEMENT)) {
9191 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
9192 if (tmp == 1)
9193 return (1);
9194 } else if (((node->type == XML_TEXT_NODE) ||
9195 (node->type == XML_CDATA_SECTION_NODE)) &&
9196 (cur->type == XML_RELAXNG_TEXT)) {
9197 return (1);
9198 }
9199 cur = list[i++];
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009200 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009201 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009202}
9203
9204/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009205 * xmlRelaxNGValidateInterleave:
9206 * @ctxt: a Relax-NG validation context
9207 * @define: the definition to verify
9208 *
9209 * Validate an interleave definition for a node.
9210 *
9211 * Returns 0 if the validation succeeded or an error code.
9212 */
9213static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009214xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
9215 xmlRelaxNGDefinePtr define)
9216{
William M. Brack779af002003-08-01 15:55:39 +00009217 int ret = 0, i, nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009218 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009219 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009220
9221 xmlRelaxNGValidStatePtr oldstate;
9222 xmlRelaxNGPartitionPtr partitions;
9223 xmlRelaxNGInterleaveGroupPtr group = NULL;
9224 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
9225 xmlNodePtr *list = NULL, *lasts = NULL;
9226
9227 if (define->data != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009228 partitions = (xmlRelaxNGPartitionPtr) define->data;
9229 nbgroups = partitions->nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009230 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009231 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
9232 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009233 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009234 /*
9235 * Optimizations for MIXED
9236 */
9237 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00009238 if (define->dflags & IS_MIXED) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009239 ctxt->flags |= FLAGS_MIXED_CONTENT;
9240 if (nbgroups == 2) {
9241 /*
9242 * this is a pure <mixed> case
9243 */
9244 if (ctxt->state != NULL)
9245 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9246 ctxt->state->seq);
9247 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
9248 ret = xmlRelaxNGValidateDefinition(ctxt,
9249 partitions->groups[1]->
9250 rule);
9251 else
9252 ret = xmlRelaxNGValidateDefinition(ctxt,
9253 partitions->groups[0]->
9254 rule);
9255 if (ret == 0) {
9256 if (ctxt->state != NULL)
9257 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9258 ctxt->state->
9259 seq);
9260 }
9261 ctxt->flags = oldflags;
9262 return (ret);
9263 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009264 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009265
9266 /*
9267 * Build arrays to store the first and last node of the chain
9268 * pertaining to each group
9269 */
9270 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9271 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009272 xmlRngVErrMemory(ctxt, "validating\n");
9273 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009274 }
9275 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
9276 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9277 if (lasts == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009278 xmlRngVErrMemory(ctxt, "validating\n");
9279 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009280 }
9281 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
9282
9283 /*
9284 * Walk the sequence of children finding the right group and
9285 * sorting them in sequences.
9286 */
9287 cur = ctxt->state->seq;
9288 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9289 start = cur;
9290 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009291 ctxt->state->seq = cur;
9292 if ((partitions->triage != NULL) &&
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009293 (partitions->flags & IS_DETERMINIST)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009294 void *tmp = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009295
Daniel Veillard4c004142003-10-07 11:33:24 +00009296 if ((cur->type == XML_TEXT_NODE) ||
9297 (cur->type == XML_CDATA_SECTION_NODE)) {
9298 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
9299 NULL);
9300 } else if (cur->type == XML_ELEMENT_NODE) {
9301 if (cur->ns != NULL) {
9302 tmp = xmlHashLookup2(partitions->triage, cur->name,
9303 cur->ns->href);
9304 if (tmp == NULL)
9305 tmp = xmlHashLookup2(partitions->triage,
9306 BAD_CAST "#any",
9307 cur->ns->href);
9308 } else
9309 tmp =
9310 xmlHashLookup2(partitions->triage, cur->name,
9311 NULL);
9312 if (tmp == NULL)
9313 tmp =
9314 xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9315 NULL);
9316 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009317
Daniel Veillard4c004142003-10-07 11:33:24 +00009318 if (tmp == NULL) {
9319 i = nbgroups;
9320 } else {
9321 i = ((long) tmp) - 1;
9322 if (partitions->flags & IS_NEEDCHECK) {
9323 group = partitions->groups[i];
9324 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9325 i = nbgroups;
9326 }
9327 }
9328 } else {
9329 for (i = 0; i < nbgroups; i++) {
9330 group = partitions->groups[i];
9331 if (group == NULL)
9332 continue;
9333 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9334 break;
9335 }
9336 }
9337 /*
9338 * We break as soon as an element not matched is found
9339 */
9340 if (i >= nbgroups) {
9341 break;
9342 }
9343 if (lasts[i] != NULL) {
9344 lasts[i]->next = cur;
9345 lasts[i] = cur;
9346 } else {
9347 list[i] = cur;
9348 lasts[i] = cur;
9349 }
9350 if (cur->next != NULL)
9351 lastchg = cur->next;
9352 else
9353 lastchg = cur;
9354 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009355 }
9356 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009357 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9358 ret = -1;
9359 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009360 }
9361 lastelem = cur;
9362 oldstate = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009363 for (i = 0; i < nbgroups; i++) {
9364 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9365 group = partitions->groups[i];
9366 if (lasts[i] != NULL) {
9367 last = lasts[i]->next;
9368 lasts[i]->next = NULL;
9369 }
9370 ctxt->state->seq = list[i];
9371 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9372 if (ret != 0)
9373 break;
9374 if (ctxt->state != NULL) {
9375 cur = ctxt->state->seq;
9376 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9377 xmlRelaxNGFreeValidState(ctxt, oldstate);
9378 oldstate = ctxt->state;
9379 ctxt->state = NULL;
9380 if (cur != NULL) {
9381 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9382 ret = -1;
9383 ctxt->state = oldstate;
9384 goto done;
9385 }
9386 } else if (ctxt->states != NULL) {
9387 int j;
9388 int found = 0;
Daniel Veillard87254c82006-02-19 15:27:17 +00009389 int best = -1;
9390 int lowattr = -1;
9391
9392 /*
9393 * PBM: what happen if there is attributes checks in the interleaves
9394 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00009395
Daniel Veillard4c004142003-10-07 11:33:24 +00009396 for (j = 0; j < ctxt->states->nbState; j++) {
9397 cur = ctxt->states->tabState[j]->seq;
9398 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9399 if (cur == NULL) {
Daniel Veillard87254c82006-02-19 15:27:17 +00009400 if (found == 0) {
9401 lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9402 best = j;
9403 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009404 found = 1;
Daniel Veillard87254c82006-02-19 15:27:17 +00009405 if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) {
9406 /* try to keep the latest one to mach old heuristic */
9407 lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9408 best = j;
9409 }
9410 if (lowattr == 0)
9411 break;
9412 } else if (found == 0) {
9413 if (lowattr == -1) {
9414 lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9415 best = j;
9416 } else
9417 if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) {
9418 /* try to keep the latest one to mach old heuristic */
9419 lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9420 best = j;
9421 }
9422 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009423 }
Daniel Veillard87254c82006-02-19 15:27:17 +00009424 /*
9425 * BIG PBM: here we pick only one restarting point :-(
9426 */
Daniel Veillard4c004142003-10-07 11:33:24 +00009427 if (ctxt->states->nbState > 0) {
9428 xmlRelaxNGFreeValidState(ctxt, oldstate);
Daniel Veillard87254c82006-02-19 15:27:17 +00009429 if (best != -1) {
9430 oldstate = ctxt->states->tabState[best];
9431 ctxt->states->tabState[best] = NULL;
9432 } else {
9433 oldstate =
9434 ctxt->states->tabState[ctxt->states->nbState - 1];
9435 ctxt->states->tabState[ctxt->states->nbState - 1] = NULL;
Daniel Veillard9fcd4622009-08-14 16:16:31 +02009436 ctxt->states->nbState--;
Daniel Veillard87254c82006-02-19 15:27:17 +00009437 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009438 }
Daniel Veillard87254c82006-02-19 15:27:17 +00009439 for (j = 0; j < ctxt->states->nbState ; j++) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009440 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
9441 }
9442 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9443 ctxt->states = NULL;
9444 if (found == 0) {
Daniel Veillard76d36452009-09-07 11:19:33 +02009445 if (cur == NULL) {
9446 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, 'noname');
9447 } else {
9448 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9449 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009450 ret = -1;
9451 ctxt->state = oldstate;
9452 goto done;
9453 }
9454 } else {
9455 ret = -1;
9456 break;
9457 }
9458 if (lasts[i] != NULL) {
9459 lasts[i]->next = last;
9460 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009461 }
9462 if (ctxt->state != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009463 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009464 ctxt->state = oldstate;
9465 ctxt->state->seq = lastelem;
9466 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009467 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9468 ret = -1;
9469 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009470 }
9471
Daniel Veillard4c004142003-10-07 11:33:24 +00009472 done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009473 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009474 /*
9475 * builds the next links chain from the prev one
9476 */
9477 cur = lastchg;
9478 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009479 if ((cur == start) || (cur->prev == NULL))
9480 break;
9481 cur->prev->next = cur;
9482 cur = cur->prev;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009483 }
9484 if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009485 if (ctxt->errNr > errNr)
9486 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009487 }
9488
9489 xmlFree(list);
9490 xmlFree(lasts);
Daniel Veillard4c004142003-10-07 11:33:24 +00009491 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009492}
9493
9494/**
9495 * xmlRelaxNGValidateDefinitionList:
9496 * @ctxt: a Relax-NG validation context
9497 * @define: the list of definition to verify
9498 *
9499 * Validate the given node content against the (list) of definitions
9500 *
9501 * Returns 0 if the validation succeeded or an error code.
9502 */
9503static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009504xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9505 xmlRelaxNGDefinePtr defines)
9506{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009507 int ret = 0, res;
9508
9509
Daniel Veillard952379b2003-03-17 15:37:12 +00009510 if (defines == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009511 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
9512 BAD_CAST "NULL definition list");
9513 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00009514 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009515 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009516 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9517 res = xmlRelaxNGValidateDefinition(ctxt, defines);
9518 if (res < 0)
9519 ret = -1;
9520 } else {
9521 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9522 return (-1);
9523 }
9524 if (res == -1) /* continues on -2 */
9525 break;
9526 defines = defines->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009527 }
9528
Daniel Veillard4c004142003-10-07 11:33:24 +00009529 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009530}
9531
9532/**
9533 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00009534 * @ctxt: a Relax-NG validation context
9535 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00009536 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00009537 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009538 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00009539 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009540 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00009541 */
9542static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009543xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9544 xmlRelaxNGDefinePtr define, xmlNodePtr elem)
9545{
Daniel Veillard580ced82003-03-21 21:22:48 +00009546 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00009547
Daniel Veillardfd573f12003-03-16 17:52:32 +00009548 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009549 if (!xmlStrEqual(elem->name, define->name)) {
9550 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9551 return (0);
9552 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009553 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009554 if ((define->ns != NULL) && (define->ns[0] != 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009555 if (elem->ns == NULL) {
9556 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
9557 return (0);
9558 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9559 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9560 elem->name, define->ns);
9561 return (0);
9562 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009563 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00009564 (define->name == NULL)) {
9565 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
9566 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009567 } else if ((elem->ns != NULL) && (define->name != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009568 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
9569 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009570 }
9571
9572 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009573 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009574
9575 define = define->nameClass;
9576 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009577 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009578
Daniel Veillard4c004142003-10-07 11:33:24 +00009579 if (ctxt != NULL) {
9580 oldflags = ctxt->flags;
9581 ctxt->flags |= FLAGS_IGNORABLE;
9582 }
9583
9584 list = define->content;
9585 while (list != NULL) {
9586 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9587 if (ret == 1) {
9588 if (ctxt != NULL)
9589 ctxt->flags = oldflags;
9590 return (0);
9591 }
9592 if (ret < 0) {
9593 if (ctxt != NULL)
9594 ctxt->flags = oldflags;
9595 return (ret);
9596 }
9597 list = list->next;
9598 }
9599 ret = 1;
9600 if (ctxt != NULL) {
9601 ctxt->flags = oldflags;
9602 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009603 } else if (define->type == XML_RELAXNG_CHOICE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009604 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009605
Daniel Veillard4c004142003-10-07 11:33:24 +00009606 if (ctxt != NULL) {
9607 oldflags = ctxt->flags;
9608 ctxt->flags |= FLAGS_IGNORABLE;
9609 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009610
Daniel Veillard4c004142003-10-07 11:33:24 +00009611 list = define->nameClass;
9612 while (list != NULL) {
9613 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9614 if (ret == 1) {
9615 if (ctxt != NULL)
9616 ctxt->flags = oldflags;
9617 return (1);
9618 }
9619 if (ret < 0) {
9620 if (ctxt != NULL)
9621 ctxt->flags = oldflags;
9622 return (ret);
9623 }
9624 list = list->next;
9625 }
9626 if (ctxt != NULL) {
9627 if (ret != 0) {
9628 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9629 xmlRelaxNGDumpValidError(ctxt);
9630 } else {
9631 if (ctxt->errNr > 0)
9632 xmlRelaxNGPopErrors(ctxt, 0);
9633 }
9634 }
9635 ret = 0;
9636 if (ctxt != NULL) {
9637 ctxt->flags = oldflags;
9638 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009639 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009640 TODO ret = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009641 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009642 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009643}
9644
9645/**
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009646 * xmlRelaxNGBestState:
9647 * @ctxt: a Relax-NG validation context
9648 *
9649 * Find the "best" state in the ctxt->states list of states to report
9650 * errors about. I.e. a state with no element left in the child list
9651 * or the one with the less attributes left.
9652 * This is called only if a falidation error was detected
9653 *
9654 * Returns the index of the "best" state or -1 in case of error
9655 */
9656static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009657xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
9658{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009659 xmlRelaxNGValidStatePtr state;
9660 int i, tmp;
9661 int best = -1;
9662 int value = 1000000;
9663
9664 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9665 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009666 return (-1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009667
Daniel Veillard4c004142003-10-07 11:33:24 +00009668 for (i = 0; i < ctxt->states->nbState; i++) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009669 state = ctxt->states->tabState[i];
Daniel Veillard4c004142003-10-07 11:33:24 +00009670 if (state == NULL)
9671 continue;
9672 if (state->seq != NULL) {
9673 if ((best == -1) || (value > 100000)) {
9674 value = 100000;
9675 best = i;
9676 }
9677 } else {
9678 tmp = state->nbAttrLeft;
9679 if ((best == -1) || (value > tmp)) {
9680 value = tmp;
9681 best = i;
9682 }
9683 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009684 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009685 return (best);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009686}
9687
9688/**
9689 * xmlRelaxNGLogBestError:
9690 * @ctxt: a Relax-NG validation context
9691 *
9692 * Find the "best" state in the ctxt->states list of states to report
9693 * errors about and log it.
9694 */
9695static void
Daniel Veillard4c004142003-10-07 11:33:24 +00009696xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
9697{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009698 int best;
9699
9700 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9701 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009702 return;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009703
9704 best = xmlRelaxNGBestState(ctxt);
9705 if ((best >= 0) && (best < ctxt->states->nbState)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009706 ctxt->state = ctxt->states->tabState[best];
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009707
Daniel Veillard4c004142003-10-07 11:33:24 +00009708 xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009709 }
9710}
9711
9712/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009713 * xmlRelaxNGValidateElementEnd:
9714 * @ctxt: a Relax-NG validation context
William M. Brack272693c2003-11-14 16:20:34 +00009715 * @dolog: indicate that error logging should be done
Daniel Veillardfd573f12003-03-16 17:52:32 +00009716 *
9717 * Validate the end of the element, implements check that
9718 * there is nothing left not consumed in the element content
9719 * or in the attribute list.
9720 *
9721 * Returns 0 if the validation succeeded or an error code.
9722 */
9723static int
William M. Brack272693c2003-11-14 16:20:34 +00009724xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
Daniel Veillard4c004142003-10-07 11:33:24 +00009725{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009726 int i;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009727 xmlRelaxNGValidStatePtr state;
9728
9729 state = ctxt->state;
9730 if (state->seq != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009731 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9732 if (state->seq != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009733 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009734 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9735 state->node->name, state->seq->name);
9736 }
9737 return (-1);
9738 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009739 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009740 for (i = 0; i < state->nbAttrs; i++) {
9741 if (state->attrs[i] != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009742 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009743 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9744 state->attrs[i]->name, state->node->name);
9745 }
9746 return (-1 - i);
9747 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009748 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009749 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009750}
9751
9752/**
9753 * xmlRelaxNGValidateState:
9754 * @ctxt: a Relax-NG validation context
9755 * @define: the definition to verify
9756 *
9757 * Validate the current state against the definition
9758 *
9759 * Returns 0 if the validation succeeded or an error code.
9760 */
9761static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009762xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9763 xmlRelaxNGDefinePtr define)
9764{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009765 xmlNodePtr node;
9766 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009767 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009768
9769 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009770 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9771 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009772 }
9773
9774 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009775 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009776 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009777 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009778 }
9779#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009780 for (i = 0; i < ctxt->depth; i++)
9781 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009782 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009783 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009784 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009785 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009786 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009787 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009788 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009789 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009790#endif
9791 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009792 switch (define->type) {
9793 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009794 node = xmlRelaxNGSkipIgnored(ctxt, node);
9795 ret = 0;
9796 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009797 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009798 ret = -1;
9799 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009800 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009801 while ((node != NULL) &&
9802 ((node->type == XML_TEXT_NODE) ||
9803 (node->type == XML_COMMENT_NODE) ||
9804 (node->type == XML_PI_NODE) ||
9805 (node->type == XML_CDATA_SECTION_NODE)))
9806 node = node->next;
9807 ctxt->state->seq = node;
9808 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009809 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009810 errNr = ctxt->errNr;
9811 node = xmlRelaxNGSkipIgnored(ctxt, node);
9812 if (node == NULL) {
9813 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9814 ret = -1;
9815 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9816 xmlRelaxNGDumpValidError(ctxt);
9817 break;
9818 }
9819 if (node->type != XML_ELEMENT_NODE) {
9820 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9821 ret = -1;
9822 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9823 xmlRelaxNGDumpValidError(ctxt);
9824 break;
9825 }
9826 /*
9827 * This node was already validated successfully against
9828 * this definition.
9829 */
Daniel Veillard807daf82004-02-22 22:13:27 +00009830 if (node->psvi == define) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009831 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9832 if (ctxt->errNr > errNr)
9833 xmlRelaxNGPopErrors(ctxt, errNr);
9834 if (ctxt->errNr != 0) {
9835 while ((ctxt->err != NULL) &&
9836 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9837 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9838 ||
9839 ((ctxt->err->err ==
9840 XML_RELAXNG_ERR_ELEMEXTRANS)
9841 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9842 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9843 || (ctxt->err->err ==
9844 XML_RELAXNG_ERR_NOTELEM)))
9845 xmlRelaxNGValidErrorPop(ctxt);
9846 }
9847 break;
9848 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009849
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009850 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9851 if (ret <= 0) {
9852 ret = -1;
9853 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9854 xmlRelaxNGDumpValidError(ctxt);
9855 break;
9856 }
9857 ret = 0;
9858 if (ctxt->errNr != 0) {
9859 if (ctxt->errNr > errNr)
9860 xmlRelaxNGPopErrors(ctxt, errNr);
9861 while ((ctxt->err != NULL) &&
9862 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9863 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9864 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9865 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9866 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9867 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9868 xmlRelaxNGValidErrorPop(ctxt);
9869 }
9870 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009871
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009872 oldflags = ctxt->flags;
9873 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9874 ctxt->flags -= FLAGS_MIXED_CONTENT;
9875 }
9876 state = xmlRelaxNGNewValidState(ctxt, node);
9877 if (state == NULL) {
9878 ret = -1;
9879 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9880 xmlRelaxNGDumpValidError(ctxt);
9881 break;
9882 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009883
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009884 oldstate = ctxt->state;
9885 ctxt->state = state;
9886 if (define->attrs != NULL) {
9887 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9888 if (tmp != 0) {
9889 ret = -1;
9890 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9891 }
9892 }
9893 if (define->contModel != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009894 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9895 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9896 xmlNodePtr nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009897
Daniel Veillard4c004142003-10-07 11:33:24 +00009898 nstate = xmlRelaxNGNewValidState(ctxt, node);
9899 ctxt->state = nstate;
9900 ctxt->states = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009901
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009902 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9903 define->contModel,
9904 ctxt->state->seq);
Daniel Veillard4c004142003-10-07 11:33:24 +00009905 nseq = ctxt->state->seq;
9906 ctxt->state = tmpstate;
9907 ctxt->states = tmpstates;
9908 xmlRelaxNGFreeValidState(ctxt, nstate);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009909
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009910#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00009911 xmlGenericError(xmlGenericErrorContext,
9912 "Validating content of '%s' : %d\n",
9913 define->name, tmp);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009914#endif
Daniel Veillardce192eb2003-04-16 15:58:05 +00009915 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00009916 ret = -1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009917
9918 if (ctxt->states != NULL) {
9919 tmp = -1;
9920
Daniel Veillardce192eb2003-04-16 15:58:05 +00009921 for (i = 0; i < ctxt->states->nbState; i++) {
9922 state = ctxt->states->tabState[i];
9923 ctxt->state = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009924 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009925
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009926 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00009927 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009928 break;
9929 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009930 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009931 if (tmp != 0) {
9932 /*
9933 * validation error, log the message for the "best" one
9934 */
9935 ctxt->flags |= FLAGS_IGNORABLE;
9936 xmlRelaxNGLogBestError(ctxt);
9937 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009938 for (i = 0; i < ctxt->states->nbState; i++) {
9939 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009940 ctxt->states->
9941 tabState[i]);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009942 }
9943 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9944 ctxt->flags = oldflags;
9945 ctxt->states = NULL;
9946 if ((ret == 0) && (tmp == -1))
9947 ret = -1;
9948 } else {
9949 state = ctxt->state;
Daniel Veillardd8ed1052007-06-12 09:24:46 +00009950 if (ctxt->state != NULL)
9951 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009952 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009953 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009954 xmlRelaxNGFreeValidState(ctxt, state);
9955 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009956 } else {
9957 if (define->content != NULL) {
9958 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009959 define->
9960 content);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009961 if (tmp != 0) {
9962 ret = -1;
9963 if (ctxt->state == NULL) {
9964 ctxt->state = oldstate;
9965 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9966 node->name);
9967 ctxt->state = NULL;
9968 } else {
9969 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9970 node->name);
9971 }
9972
9973 }
9974 }
9975 if (ctxt->states != NULL) {
9976 tmp = -1;
9977
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009978 for (i = 0; i < ctxt->states->nbState; i++) {
9979 state = ctxt->states->tabState[i];
9980 ctxt->state = state;
9981
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009982 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009983 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009984 break;
9985 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009986 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009987 if (tmp != 0) {
9988 /*
9989 * validation error, log the message for the "best" one
9990 */
9991 ctxt->flags |= FLAGS_IGNORABLE;
9992 xmlRelaxNGLogBestError(ctxt);
9993 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009994 for (i = 0; i < ctxt->states->nbState; i++) {
9995 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard9fcd4622009-08-14 16:16:31 +02009996 ctxt->states->tabState[i]);
9997 ctxt->states->tabState[i] = NULL;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009998 }
9999 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10000 ctxt->flags = oldflags;
10001 ctxt->states = NULL;
10002 if ((ret == 0) && (tmp == -1))
10003 ret = -1;
10004 } else {
10005 state = ctxt->state;
10006 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +000010007 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010008 xmlRelaxNGFreeValidState(ctxt, state);
10009 }
10010 }
10011 if (ret == 0) {
Daniel Veillard807daf82004-02-22 22:13:27 +000010012 node->psvi = define;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010013 }
10014 ctxt->flags = oldflags;
10015 ctxt->state = oldstate;
10016 if (oldstate != NULL)
10017 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
10018 if (ret != 0) {
10019 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10020 xmlRelaxNGDumpValidError(ctxt);
10021 ret = 0;
Daniel Veillardfa0d0942006-10-13 16:30:56 +000010022#if 0
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010023 } else {
10024 ret = -2;
Daniel Veillardfa0d0942006-10-13 16:30:56 +000010025#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010026 }
10027 } else {
10028 if (ctxt->errNr > errNr)
10029 xmlRelaxNGPopErrors(ctxt, errNr);
10030 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010031
10032#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010033 xmlGenericError(xmlGenericErrorContext,
10034 "xmlRelaxNGValidateDefinition(): validated %s : %d",
10035 node->name, ret);
10036 if (oldstate == NULL)
10037 xmlGenericError(xmlGenericErrorContext, ": no state\n");
10038 else if (oldstate->seq == NULL)
10039 xmlGenericError(xmlGenericErrorContext, ": done\n");
10040 else if (oldstate->seq->type == XML_ELEMENT_NODE)
10041 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
10042 oldstate->seq->name);
10043 else
10044 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
10045 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010046#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010047 break;
10048 case XML_RELAXNG_OPTIONAL:{
10049 errNr = ctxt->errNr;
10050 oldflags = ctxt->flags;
10051 ctxt->flags |= FLAGS_IGNORABLE;
10052 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10053 ret =
10054 xmlRelaxNGValidateDefinitionList(ctxt,
10055 define->content);
10056 if (ret != 0) {
10057 if (ctxt->state != NULL)
10058 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10059 ctxt->state = oldstate;
10060 ctxt->flags = oldflags;
10061 ret = 0;
10062 if (ctxt->errNr > errNr)
10063 xmlRelaxNGPopErrors(ctxt, errNr);
10064 break;
10065 }
10066 if (ctxt->states != NULL) {
10067 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
10068 } else {
10069 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
10070 if (ctxt->states == NULL) {
10071 xmlRelaxNGFreeValidState(ctxt, oldstate);
10072 ctxt->flags = oldflags;
10073 ret = -1;
10074 if (ctxt->errNr > errNr)
10075 xmlRelaxNGPopErrors(ctxt, errNr);
10076 break;
10077 }
10078 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
10079 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
10080 ctxt->state = NULL;
10081 }
10082 ctxt->flags = oldflags;
10083 ret = 0;
10084 if (ctxt->errNr > errNr)
10085 xmlRelaxNGPopErrors(ctxt, errNr);
10086 break;
10087 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010088 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010089 errNr = ctxt->errNr;
10090 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10091 if (ret != 0) {
10092 break;
10093 }
10094 if (ctxt->errNr > errNr)
10095 xmlRelaxNGPopErrors(ctxt, errNr);
10096 /* no break on purpose */
10097 case XML_RELAXNG_ZEROORMORE:{
10098 int progress;
10099 xmlRelaxNGStatesPtr states = NULL, res = NULL;
10100 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010101
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010102 errNr = ctxt->errNr;
10103 res = xmlRelaxNGNewStates(ctxt, 1);
10104 if (res == NULL) {
10105 ret = -1;
10106 break;
10107 }
10108 /*
10109 * All the input states are also exit states
10110 */
10111 if (ctxt->state != NULL) {
10112 xmlRelaxNGAddStates(ctxt, res,
10113 xmlRelaxNGCopyValidState(ctxt,
10114 ctxt->
10115 state));
10116 } else {
10117 for (j = 0; j < ctxt->states->nbState; j++) {
10118 xmlRelaxNGAddStates(ctxt, res,
Daniel Veillard9fcd4622009-08-14 16:16:31 +020010119 xmlRelaxNGCopyValidState(ctxt,
10120 ctxt->states->tabState[j]));
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010121 }
10122 }
10123 oldflags = ctxt->flags;
10124 ctxt->flags |= FLAGS_IGNORABLE;
10125 do {
10126 progress = 0;
10127 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010128
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010129 if (ctxt->states != NULL) {
10130 states = ctxt->states;
10131 for (i = 0; i < states->nbState; i++) {
10132 ctxt->state = states->tabState[i];
10133 ctxt->states = NULL;
10134 ret = xmlRelaxNGValidateDefinitionList(ctxt,
10135 define->
10136 content);
10137 if (ret == 0) {
10138 if (ctxt->state != NULL) {
10139 tmp = xmlRelaxNGAddStates(ctxt, res,
10140 ctxt->state);
10141 ctxt->state = NULL;
10142 if (tmp == 1)
10143 progress = 1;
10144 } else if (ctxt->states != NULL) {
10145 for (j = 0; j < ctxt->states->nbState;
10146 j++) {
10147 tmp =
10148 xmlRelaxNGAddStates(ctxt, res,
Daniel Veillard9fcd4622009-08-14 16:16:31 +020010149 ctxt->states->tabState[j]);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010150 if (tmp == 1)
10151 progress = 1;
10152 }
10153 xmlRelaxNGFreeStates(ctxt,
10154 ctxt->states);
10155 ctxt->states = NULL;
10156 }
10157 } else {
10158 if (ctxt->state != NULL) {
10159 xmlRelaxNGFreeValidState(ctxt,
10160 ctxt->state);
10161 ctxt->state = NULL;
10162 }
10163 }
10164 }
10165 } else {
10166 ret = xmlRelaxNGValidateDefinitionList(ctxt,
10167 define->
10168 content);
10169 if (ret != 0) {
10170 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10171 ctxt->state = NULL;
10172 } else {
10173 base = res->nbState;
10174 if (ctxt->state != NULL) {
10175 tmp = xmlRelaxNGAddStates(ctxt, res,
10176 ctxt->state);
10177 ctxt->state = NULL;
10178 if (tmp == 1)
10179 progress = 1;
10180 } else if (ctxt->states != NULL) {
10181 for (j = 0; j < ctxt->states->nbState; j++) {
10182 tmp = xmlRelaxNGAddStates(ctxt, res,
Daniel Veillard9fcd4622009-08-14 16:16:31 +020010183 ctxt->states->tabState[j]);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010184 if (tmp == 1)
10185 progress = 1;
10186 }
10187 if (states == NULL) {
10188 states = ctxt->states;
10189 } else {
10190 xmlRelaxNGFreeStates(ctxt,
10191 ctxt->states);
10192 }
10193 ctxt->states = NULL;
10194 }
10195 }
10196 }
10197 if (progress) {
10198 /*
10199 * Collect all the new nodes added at that step
10200 * and make them the new node set
10201 */
10202 if (res->nbState - base == 1) {
10203 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
10204 res->
10205 tabState
10206 [base]);
10207 } else {
10208 if (states == NULL) {
10209 xmlRelaxNGNewStates(ctxt,
10210 res->nbState - base);
Daniel Veillard14b56432006-03-09 18:41:40 +000010211 states = ctxt->states;
10212 if (states == NULL) {
10213 progress = 0;
10214 break;
10215 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010216 }
10217 states->nbState = 0;
10218 for (i = base; i < res->nbState; i++)
10219 xmlRelaxNGAddStates(ctxt, states,
10220 xmlRelaxNGCopyValidState
Daniel Veillard9fcd4622009-08-14 16:16:31 +020010221 (ctxt, res->tabState[i]));
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010222 ctxt->states = states;
10223 }
10224 }
10225 } while (progress == 1);
10226 if (states != NULL) {
10227 xmlRelaxNGFreeStates(ctxt, states);
10228 }
10229 ctxt->states = res;
10230 ctxt->flags = oldflags;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010231#if 0
10232 /*
Daniel Veillard4c004142003-10-07 11:33:24 +000010233 * errors may have to be propagated back...
10234 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010235 if (ctxt->errNr > errNr)
10236 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010237#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010238 ret = 0;
10239 break;
10240 }
10241 case XML_RELAXNG_CHOICE:{
10242 xmlRelaxNGDefinePtr list = NULL;
10243 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010244
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010245 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010246
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010247 errNr = ctxt->errNr;
Daniel Veillard9186a1f2005-01-15 12:38:10 +000010248 if ((define->dflags & IS_TRIABLE) && (define->data != NULL) &&
10249 (node != NULL)) {
10250 /*
10251 * node == NULL can't be optimized since IS_TRIABLE
10252 * doesn't account for choice which may lead to
10253 * only attributes.
10254 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010255 xmlHashTablePtr triage =
10256 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +000010257
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010258 /*
10259 * Something we can optimize cleanly there is only one
10260 * possble branch out !
10261 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010262 if ((node->type == XML_TEXT_NODE) ||
10263 (node->type == XML_CDATA_SECTION_NODE)) {
10264 list =
10265 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10266 } else if (node->type == XML_ELEMENT_NODE) {
10267 if (node->ns != NULL) {
10268 list = xmlHashLookup2(triage, node->name,
10269 node->ns->href);
10270 if (list == NULL)
10271 list =
10272 xmlHashLookup2(triage, BAD_CAST "#any",
10273 node->ns->href);
10274 } else
10275 list =
10276 xmlHashLookup2(triage, node->name, NULL);
10277 if (list == NULL)
10278 list =
10279 xmlHashLookup2(triage, BAD_CAST "#any",
10280 NULL);
10281 }
10282 if (list == NULL) {
10283 ret = -1;
William M. Brack2f076062004-03-21 11:21:14 +000010284 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010285 break;
10286 }
10287 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10288 if (ret == 0) {
10289 }
10290 break;
10291 }
Daniel Veillarde063f482003-03-21 16:53:17 +000010292
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010293 list = define->content;
10294 oldflags = ctxt->flags;
10295 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010296
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010297 while (list != NULL) {
10298 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10299 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10300 if (ret == 0) {
10301 if (states == NULL) {
10302 states = xmlRelaxNGNewStates(ctxt, 1);
10303 }
10304 if (ctxt->state != NULL) {
10305 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10306 } else if (ctxt->states != NULL) {
10307 for (i = 0; i < ctxt->states->nbState; i++) {
10308 xmlRelaxNGAddStates(ctxt, states,
10309 ctxt->states->
10310 tabState[i]);
10311 }
10312 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10313 ctxt->states = NULL;
10314 }
10315 } else {
10316 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10317 }
10318 ctxt->state = oldstate;
10319 list = list->next;
10320 }
10321 if (states != NULL) {
10322 xmlRelaxNGFreeValidState(ctxt, oldstate);
10323 ctxt->states = states;
10324 ctxt->state = NULL;
10325 ret = 0;
10326 } else {
10327 ctxt->states = NULL;
10328 }
10329 ctxt->flags = oldflags;
10330 if (ret != 0) {
10331 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10332 xmlRelaxNGDumpValidError(ctxt);
10333 }
10334 } else {
10335 if (ctxt->errNr > errNr)
10336 xmlRelaxNGPopErrors(ctxt, errNr);
10337 }
10338 break;
10339 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010340 case XML_RELAXNG_DEF:
10341 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010342 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10343 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010344 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010345 ret = xmlRelaxNGValidateInterleave(ctxt, define);
10346 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010347 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010348 ret = xmlRelaxNGValidateAttribute(ctxt, define);
10349 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +000010350 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010351 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +000010352 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010353 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +000010354 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010355 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10356 break;
10357 case XML_RELAXNG_DATATYPE:{
10358 xmlNodePtr child;
10359 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010360
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010361 child = node;
10362 while (child != NULL) {
10363 if (child->type == XML_ELEMENT_NODE) {
10364 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10365 node->parent->name);
10366 ret = -1;
10367 break;
10368 } else if ((child->type == XML_TEXT_NODE) ||
10369 (child->type == XML_CDATA_SECTION_NODE)) {
10370 content = xmlStrcat(content, child->content);
10371 }
10372 /* TODO: handle entities ... */
10373 child = child->next;
10374 }
10375 if (ret == -1) {
10376 if (content != NULL)
10377 xmlFree(content);
10378 break;
10379 }
10380 if (content == NULL) {
10381 content = xmlStrdup(BAD_CAST "");
10382 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010383 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010384 ret = -1;
10385 break;
10386 }
10387 }
10388 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10389 ctxt->state->seq);
10390 if (ret == -1) {
10391 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10392 } else if (ret == 0) {
10393 ctxt->state->seq = NULL;
10394 }
10395 if (content != NULL)
10396 xmlFree(content);
10397 break;
10398 }
10399 case XML_RELAXNG_VALUE:{
10400 xmlChar *content = NULL;
10401 xmlChar *oldvalue;
10402 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010403
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010404 child = node;
10405 while (child != NULL) {
10406 if (child->type == XML_ELEMENT_NODE) {
10407 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10408 node->parent->name);
10409 ret = -1;
10410 break;
10411 } else if ((child->type == XML_TEXT_NODE) ||
10412 (child->type == XML_CDATA_SECTION_NODE)) {
10413 content = xmlStrcat(content, child->content);
10414 }
10415 /* TODO: handle entities ... */
10416 child = child->next;
10417 }
10418 if (ret == -1) {
10419 if (content != NULL)
10420 xmlFree(content);
10421 break;
10422 }
10423 if (content == NULL) {
10424 content = xmlStrdup(BAD_CAST "");
10425 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010426 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010427 ret = -1;
10428 break;
10429 }
10430 }
10431 oldvalue = ctxt->state->value;
10432 ctxt->state->value = content;
10433 ret = xmlRelaxNGValidateValue(ctxt, define);
10434 ctxt->state->value = oldvalue;
10435 if (ret == -1) {
10436 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10437 } else if (ret == 0) {
10438 ctxt->state->seq = NULL;
10439 }
10440 if (content != NULL)
10441 xmlFree(content);
10442 break;
10443 }
10444 case XML_RELAXNG_LIST:{
10445 xmlChar *content;
10446 xmlNodePtr child;
10447 xmlChar *oldvalue, *oldendvalue;
10448 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010449
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010450 /*
10451 * Make sure it's only text nodes
10452 */
10453
10454 content = NULL;
10455 child = node;
10456 while (child != NULL) {
10457 if (child->type == XML_ELEMENT_NODE) {
10458 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10459 node->parent->name);
10460 ret = -1;
10461 break;
10462 } else if ((child->type == XML_TEXT_NODE) ||
10463 (child->type == XML_CDATA_SECTION_NODE)) {
10464 content = xmlStrcat(content, child->content);
10465 }
10466 /* TODO: handle entities ... */
10467 child = child->next;
10468 }
10469 if (ret == -1) {
10470 if (content != NULL)
10471 xmlFree(content);
10472 break;
10473 }
10474 if (content == NULL) {
10475 content = xmlStrdup(BAD_CAST "");
10476 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010477 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010478 ret = -1;
10479 break;
10480 }
10481 }
10482 len = xmlStrlen(content);
10483 oldvalue = ctxt->state->value;
10484 oldendvalue = ctxt->state->endvalue;
10485 ctxt->state->value = content;
10486 ctxt->state->endvalue = content + len;
10487 ret = xmlRelaxNGValidateValue(ctxt, define);
10488 ctxt->state->value = oldvalue;
10489 ctxt->state->endvalue = oldendvalue;
10490 if (ret == -1) {
10491 VALID_ERR(XML_RELAXNG_ERR_LIST);
10492 } else if ((ret == 0) && (node != NULL)) {
10493 ctxt->state->seq = node->next;
10494 }
10495 if (content != NULL)
10496 xmlFree(content);
10497 break;
10498 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010499 case XML_RELAXNG_EXCEPT:
10500 case XML_RELAXNG_PARAM:
10501 TODO ret = -1;
10502 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010503 }
10504 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010505#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010506 for (i = 0; i < ctxt->depth; i++)
10507 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010508 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010509 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +000010510 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010511 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010512 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010513 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010514 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010515 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010516#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010517 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010518}
10519
10520/**
Daniel Veillardfd573f12003-03-16 17:52:32 +000010521 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010522 * @ctxt: a Relax-NG validation context
10523 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010524 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010525 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010526 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010527 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010528 */
10529static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010530xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10531 xmlRelaxNGDefinePtr define)
10532{
Daniel Veillardfd573f12003-03-16 17:52:32 +000010533 xmlRelaxNGStatesPtr states, res;
10534 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010535
Daniel Veillardfd573f12003-03-16 17:52:32 +000010536 /*
10537 * We should NOT have both ctxt->state and ctxt->states
10538 */
10539 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010540 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10541 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010542 }
10543
10544 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010545 if (ctxt->states != NULL) {
10546 ctxt->state = ctxt->states->tabState[0];
10547 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10548 ctxt->states = NULL;
10549 }
10550 ret = xmlRelaxNGValidateState(ctxt, define);
10551 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10552 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10553 ctxt->state = NULL;
10554 }
10555 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10556 ctxt->state = ctxt->states->tabState[0];
10557 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10558 ctxt->states = NULL;
10559 }
10560 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010561 }
10562
10563 states = ctxt->states;
10564 ctxt->states = NULL;
10565 res = NULL;
10566 j = 0;
10567 oldflags = ctxt->flags;
10568 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +000010569 for (i = 0; i < states->nbState; i++) {
10570 ctxt->state = states->tabState[i];
10571 ctxt->states = NULL;
10572 ret = xmlRelaxNGValidateState(ctxt, define);
10573 /*
10574 * We should NOT have both ctxt->state and ctxt->states
10575 */
10576 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10577 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10578 ctxt->state = NULL;
10579 }
10580 if (ret == 0) {
10581 if (ctxt->states == NULL) {
10582 if (res != NULL) {
10583 /* add the state to the container */
10584 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10585 ctxt->state = NULL;
10586 } else {
10587 /* add the state directly in states */
10588 states->tabState[j++] = ctxt->state;
10589 ctxt->state = NULL;
10590 }
10591 } else {
10592 if (res == NULL) {
10593 /* make it the new container and copy other results */
10594 res = ctxt->states;
10595 ctxt->states = NULL;
10596 for (k = 0; k < j; k++)
10597 xmlRelaxNGAddStates(ctxt, res,
10598 states->tabState[k]);
10599 } else {
10600 /* add all the new results to res and reff the container */
10601 for (k = 0; k < ctxt->states->nbState; k++)
10602 xmlRelaxNGAddStates(ctxt, res,
10603 ctxt->states->tabState[k]);
10604 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10605 ctxt->states = NULL;
10606 }
10607 }
10608 } else {
10609 if (ctxt->state != NULL) {
10610 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10611 ctxt->state = NULL;
10612 } else if (ctxt->states != NULL) {
10613 for (k = 0; k < ctxt->states->nbState; k++)
10614 xmlRelaxNGFreeValidState(ctxt,
10615 ctxt->states->tabState[k]);
10616 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10617 ctxt->states = NULL;
10618 }
10619 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010620 }
10621 ctxt->flags = oldflags;
10622 if (res != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010623 xmlRelaxNGFreeStates(ctxt, states);
10624 ctxt->states = res;
10625 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010626 } else if (j > 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010627 states->nbState = j;
10628 ctxt->states = states;
10629 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010630 } else if (j == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010631 ctxt->state = states->tabState[0];
10632 xmlRelaxNGFreeStates(ctxt, states);
10633 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010634 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +000010635 ret = -1;
10636 xmlRelaxNGFreeStates(ctxt, states);
10637 if (ctxt->states != NULL) {
10638 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10639 ctxt->states = NULL;
10640 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010641 }
10642 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010643 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10644 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010645 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010646 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010647}
10648
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010649/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010650 * xmlRelaxNGValidateDocument:
10651 * @ctxt: a Relax-NG validation context
10652 * @doc: the document
10653 *
10654 * Validate the given document
10655 *
10656 * Returns 0 if the validation succeeded or an error code.
10657 */
10658static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010659xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10660{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010661 int ret;
10662 xmlRelaxNGPtr schema;
10663 xmlRelaxNGGrammarPtr grammar;
10664 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010665 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010666
10667 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010668 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010669
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010670 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010671 schema = ctxt->schema;
10672 grammar = schema->topgrammar;
10673 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010674 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10675 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010676 }
10677 state = xmlRelaxNGNewValidState(ctxt, NULL);
10678 ctxt->state = state;
10679 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010680 if ((ctxt->state != NULL) && (state->seq != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010681 state = ctxt->state;
10682 node = state->seq;
10683 node = xmlRelaxNGSkipIgnored(ctxt, node);
10684 if (node != NULL) {
10685 if (ret != -1) {
10686 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10687 ret = -1;
10688 }
10689 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010690 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010691 int i;
10692 int tmp = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010693
Daniel Veillard4c004142003-10-07 11:33:24 +000010694 for (i = 0; i < ctxt->states->nbState; i++) {
10695 state = ctxt->states->tabState[i];
10696 node = state->seq;
10697 node = xmlRelaxNGSkipIgnored(ctxt, node);
10698 if (node == NULL)
10699 tmp = 0;
10700 xmlRelaxNGFreeValidState(ctxt, state);
10701 }
10702 if (tmp == -1) {
10703 if (ret != -1) {
10704 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10705 ret = -1;
10706 }
10707 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010708 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010709 if (ctxt->state != NULL) {
10710 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillard4c004142003-10-07 11:33:24 +000010711 ctxt->state = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010712 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010713 if (ret != 0)
10714 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010715#ifdef DEBUG
10716 else if (ctxt->errNr != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010717 ctxt->error(ctxt->userData,
10718 "%d Extra error messages left on stack !\n",
10719 ctxt->errNr);
10720 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010721 }
10722#endif
Daniel Veillardf54cd532004-02-25 11:52:31 +000010723#ifdef LIBXML_VALID_ENABLED
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010724 if (ctxt->idref == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010725 xmlValidCtxt vctxt;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010726
Daniel Veillard4c004142003-10-07 11:33:24 +000010727 memset(&vctxt, 0, sizeof(xmlValidCtxt));
10728 vctxt.valid = 1;
10729 vctxt.error = ctxt->error;
10730 vctxt.warning = ctxt->warning;
10731 vctxt.userData = ctxt->userData;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010732
Daniel Veillard4c004142003-10-07 11:33:24 +000010733 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10734 ret = -1;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010735 }
Daniel Veillardf54cd532004-02-25 11:52:31 +000010736#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010737 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
Daniel Veillard4c004142003-10-07 11:33:24 +000010738 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010739
Daniel Veillard4c004142003-10-07 11:33:24 +000010740 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010741}
10742
Daniel Veillarda4f27cb2009-08-21 17:34:17 +020010743/**
10744 * xmlRelaxNGCleanPSVI:
10745 * @node: an input element or document
10746 *
10747 * Call this routine to speed up XPath computation on static documents.
10748 * This stamps all the element nodes with the document order
10749 * Like for line information, the order is kept in the element->content
10750 * field, the value stored is actually - the node number (starting at -1)
10751 * to be able to differentiate from line numbers.
10752 *
10753 * Returns the number of elements found in the document or -1 in case
10754 * of error.
10755 */
10756static void
10757xmlRelaxNGCleanPSVI(xmlNodePtr node) {
10758 xmlNodePtr cur;
10759
10760 if ((node == NULL) ||
10761 ((node->type != XML_ELEMENT_NODE) &&
10762 (node->type != XML_DOCUMENT_NODE) &&
10763 (node->type != XML_HTML_DOCUMENT_NODE)))
10764 return;
10765 if (node->type == XML_ELEMENT_NODE)
10766 node->psvi = NULL;
10767
10768 cur = node->children;
10769 while (cur != NULL) {
10770 if (cur->type == XML_ELEMENT_NODE) {
10771 cur->psvi = NULL;
10772 if (cur->children != NULL) {
10773 cur = cur->children;
10774 continue;
10775 }
10776 }
10777 if (cur->next != NULL) {
10778 cur = cur->next;
10779 continue;
10780 }
10781 do {
10782 cur = cur->parent;
10783 if (cur == NULL)
10784 break;
10785 if (cur == node) {
10786 cur = NULL;
10787 break;
10788 }
10789 if (cur->next != NULL) {
10790 cur = cur->next;
10791 break;
10792 }
10793 } while (cur != NULL);
10794 }
10795 return;
10796}
Daniel Veillardfd573f12003-03-16 17:52:32 +000010797/************************************************************************
10798 * *
10799 * Validation interfaces *
10800 * *
10801 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +000010802
Daniel Veillard6eadf632003-01-23 18:29:16 +000010803/**
10804 * xmlRelaxNGNewValidCtxt:
10805 * @schema: a precompiled XML RelaxNGs
10806 *
10807 * Create an XML RelaxNGs validation context based on the given schema
10808 *
10809 * Returns the validation context or NULL in case of error
10810 */
10811xmlRelaxNGValidCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +000010812xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10813{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010814 xmlRelaxNGValidCtxtPtr ret;
10815
10816 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10817 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010818 xmlRngVErrMemory(NULL, "building context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +000010819 return (NULL);
10820 }
10821 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10822 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +000010823 ret->error = xmlGenericError;
10824 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +000010825 ret->errNr = 0;
10826 ret->errMax = 0;
10827 ret->err = NULL;
10828 ret->errTab = NULL;
Daniel Veillardb30ca312005-09-04 13:50:03 +000010829 if (schema != NULL)
10830 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +000010831 ret->states = NULL;
10832 ret->freeState = NULL;
10833 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010834 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010835 return (ret);
10836}
10837
10838/**
10839 * xmlRelaxNGFreeValidCtxt:
10840 * @ctxt: the schema validation context
10841 *
10842 * Free the resources associated to the schema validation context
10843 */
10844void
Daniel Veillard4c004142003-10-07 11:33:24 +000010845xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10846{
Daniel Veillard798024a2003-03-19 10:36:09 +000010847 int k;
10848
Daniel Veillard6eadf632003-01-23 18:29:16 +000010849 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010850 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010851 if (ctxt->states != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010852 xmlRelaxNGFreeStates(NULL, ctxt->states);
Daniel Veillard798024a2003-03-19 10:36:09 +000010853 if (ctxt->freeState != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010854 for (k = 0; k < ctxt->freeState->nbState; k++) {
10855 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10856 }
10857 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
Daniel Veillard798024a2003-03-19 10:36:09 +000010858 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010859 if (ctxt->freeStates != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010860 for (k = 0; k < ctxt->freeStatesNr; k++) {
10861 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10862 }
10863 xmlFree(ctxt->freeStates);
Daniel Veillard798024a2003-03-19 10:36:09 +000010864 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010865 if (ctxt->errTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010866 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010867 if (ctxt->elemTab != NULL) {
10868 xmlRegExecCtxtPtr exec;
10869
Daniel Veillard4c004142003-10-07 11:33:24 +000010870 exec = xmlRelaxNGElemPop(ctxt);
10871 while (exec != NULL) {
10872 xmlRegFreeExecCtxt(exec);
10873 exec = xmlRelaxNGElemPop(ctxt);
10874 }
10875 xmlFree(ctxt->elemTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010876 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010877 xmlFree(ctxt);
10878}
10879
10880/**
10881 * xmlRelaxNGSetValidErrors:
10882 * @ctxt: a Relax-NG validation context
10883 * @err: the error function
10884 * @warn: the warning function
10885 * @ctx: the functions context
10886 *
10887 * Set the error and warning callback informations
10888 */
10889void
10890xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010891 xmlRelaxNGValidityErrorFunc err,
10892 xmlRelaxNGValidityWarningFunc warn, void *ctx)
10893{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010894 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010895 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010896 ctxt->error = err;
10897 ctxt->warning = warn;
10898 ctxt->userData = ctx;
Daniel Veillardb30ca312005-09-04 13:50:03 +000010899 ctxt->serror = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010900}
10901
10902/**
Daniel Veillardda0aa4c2005-07-13 23:07:49 +000010903 * xmlRelaxNGSetValidStructuredErrors:
10904 * @ctxt: a Relax-NG validation context
10905 * @serror: the structured error function
10906 * @ctx: the functions context
10907 *
10908 * Set the structured error callback
10909 */
10910void
10911xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillardb30ca312005-09-04 13:50:03 +000010912 xmlStructuredErrorFunc serror, void *ctx)
Daniel Veillardda0aa4c2005-07-13 23:07:49 +000010913{
10914 if (ctxt == NULL)
10915 return;
Daniel Veillardb30ca312005-09-04 13:50:03 +000010916 ctxt->serror = serror;
Daniel Veillardda0aa4c2005-07-13 23:07:49 +000010917 ctxt->error = NULL;
10918 ctxt->warning = NULL;
10919 ctxt->userData = ctx;
10920}
10921
10922/**
Daniel Veillard409a8142003-07-18 15:16:57 +000010923 * xmlRelaxNGGetValidErrors:
10924 * @ctxt: a Relax-NG validation context
10925 * @err: the error function result
10926 * @warn: the warning function result
10927 * @ctx: the functions context result
10928 *
10929 * Get the error and warning callback informations
10930 *
10931 * Returns -1 in case of error and 0 otherwise
10932 */
10933int
10934xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010935 xmlRelaxNGValidityErrorFunc * err,
10936 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
10937{
Daniel Veillard409a8142003-07-18 15:16:57 +000010938 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010939 return (-1);
10940 if (err != NULL)
10941 *err = ctxt->error;
10942 if (warn != NULL)
10943 *warn = ctxt->warning;
10944 if (ctx != NULL)
10945 *ctx = ctxt->userData;
10946 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +000010947}
10948
10949/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010950 * xmlRelaxNGValidateDoc:
10951 * @ctxt: a Relax-NG validation context
10952 * @doc: a parsed document tree
10953 *
10954 * Validate a document tree in memory.
10955 *
10956 * Returns 0 if the document is valid, a positive error code
10957 * number otherwise and -1 in case of internal or API error.
10958 */
10959int
Daniel Veillard4c004142003-10-07 11:33:24 +000010960xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10961{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010962 int ret;
10963
10964 if ((ctxt == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010965 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010966
10967 ctxt->doc = doc;
10968
10969 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010970 /*
Daniel Veillarda4f27cb2009-08-21 17:34:17 +020010971 * Remove all left PSVI
10972 */
10973 xmlRelaxNGCleanPSVI((xmlNodePtr) doc);
10974
10975 /*
Daniel Veillard71531f32003-02-05 13:19:53 +000010976 * TODO: build error codes
10977 */
10978 if (ret == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +000010979 return (1);
10980 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010981}
10982
Daniel Veillard5d4644e2005-04-01 13:11:58 +000010983#define bottom_relaxng
10984#include "elfgcchack.h"
Daniel Veillard6eadf632003-01-23 18:29:16 +000010985#endif /* LIBXML_SCHEMAS_ENABLED */