blob: 1fd46e9138cce0fcb52011560ef51d85c1d814b0 [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 Veillard952379b2003-03-17 15:37:12 +000048/* #define DEBUG 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000049
Daniel Veillardc482e262003-02-26 14:48:48 +000050/* #define DEBUG_GRAMMAR 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000051
Daniel Veillard71531f32003-02-05 13:19:53 +000052/* #define DEBUG_CONTENT 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000053
Daniel Veillard71531f32003-02-05 13:19:53 +000054/* #define DEBUG_TYPE 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000055
Daniel Veillard71531f32003-02-05 13:19:53 +000056/* #define DEBUG_VALID 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000057
Daniel Veillarde5b110b2003-02-04 14:43:39 +000058/* #define DEBUG_INTERLEAVE 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000059
Daniel Veillard416589a2003-02-17 17:25:42 +000060/* #define DEBUG_LIST 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000061
Daniel Veillard5add8682003-03-10 13:13:58 +000062/* #define DEBUG_INCLUDE */
Daniel Veillard4c004142003-10-07 11:33:24 +000063
Daniel Veillarda507fbf2003-03-31 16:09:37 +000064/* #define DEBUG_ERROR 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000065
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000066/* #define DEBUG_COMPILE 1 */
Daniel Veillard4c004142003-10-07 11:33:24 +000067
Daniel Veillardf4e55762003-04-15 23:32:22 +000068/* #define DEBUG_PROGRESSIVE 1 */
Daniel Veillard6eadf632003-01-23 18:29:16 +000069
Daniel Veillard5f1946a2003-03-31 16:38:16 +000070#define MAX_ERROR 5
71
Daniel Veillard6eadf632003-01-23 18:29:16 +000072#define TODO \
73 xmlGenericError(xmlGenericErrorContext, \
74 "Unimplemented block at %s:%d\n", \
75 __FILE__, __LINE__);
76
77typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
78typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
79
80typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
81typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
82
Daniel Veillardd41f4f42003-01-29 21:07:52 +000083typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
84typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
85
Daniel Veillarda9d912d2003-02-01 17:43:10 +000086typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
87typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
88
Daniel Veillard6eadf632003-01-23 18:29:16 +000089typedef enum {
Daniel Veillard4c004142003-10-07 11:33:24 +000090 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
91 XML_RELAXNG_COMBINE_CHOICE, /* choice */
92 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
Daniel Veillard6eadf632003-01-23 18:29:16 +000093} xmlRelaxNGCombine;
94
Daniel Veillard4c5cf702003-02-21 15:40:34 +000095typedef enum {
96 XML_RELAXNG_CONTENT_ERROR = -1,
97 XML_RELAXNG_CONTENT_EMPTY = 0,
98 XML_RELAXNG_CONTENT_SIMPLE,
99 XML_RELAXNG_CONTENT_COMPLEX
100} xmlRelaxNGContentType;
101
Daniel Veillard6eadf632003-01-23 18:29:16 +0000102typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
103typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
104
105struct _xmlRelaxNGGrammar {
Daniel Veillard4c004142003-10-07 11:33:24 +0000106 xmlRelaxNGGrammarPtr parent; /* the parent grammar if any */
107 xmlRelaxNGGrammarPtr children; /* the children grammar if any */
108 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
109 xmlRelaxNGDefinePtr start; /* <start> content */
110 xmlRelaxNGCombine combine; /* the default combine value */
111 xmlRelaxNGDefinePtr startList; /* list of <start> definitions */
112 xmlHashTablePtr defs; /* define* */
113 xmlHashTablePtr refs; /* references */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000114};
115
116
Daniel Veillard6eadf632003-01-23 18:29:16 +0000117typedef enum {
Daniel Veillard4c004142003-10-07 11:33:24 +0000118 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
119 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000120 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard4c004142003-10-07 11:33:24 +0000121 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
122 XML_RELAXNG_TEXT, /* textual content */
123 XML_RELAXNG_ELEMENT, /* an element */
124 XML_RELAXNG_DATATYPE, /* extenal data type definition */
125 XML_RELAXNG_PARAM, /* extenal data type parameter */
126 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
127 XML_RELAXNG_LIST, /* a list of patterns */
128 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
129 XML_RELAXNG_DEF, /* a definition */
130 XML_RELAXNG_REF, /* reference to a definition */
131 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
132 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
133 XML_RELAXNG_OPTIONAL, /* optional patterns */
134 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
135 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
136 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
137 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
138 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
139 XML_RELAXNG_START /* Used to keep track of starts on grammars */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000140} xmlRelaxNGType;
141
Daniel Veillard52b48c72003-04-13 19:53:42 +0000142#define IS_NULLABLE (1 << 0)
143#define IS_NOT_NULLABLE (1 << 1)
144#define IS_INDETERMINIST (1 << 2)
145#define IS_MIXED (1 << 3)
146#define IS_TRIABLE (1 << 4)
147#define IS_PROCESSED (1 << 5)
148#define IS_COMPILABLE (1 << 6)
149#define IS_NOT_COMPILABLE (1 << 7)
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000150
Daniel Veillard6eadf632003-01-23 18:29:16 +0000151struct _xmlRelaxNGDefine {
Daniel Veillard4c004142003-10-07 11:33:24 +0000152 xmlRelaxNGType type; /* the type of definition */
153 xmlNodePtr node; /* the node in the source */
154 xmlChar *name; /* the element local name if present */
155 xmlChar *ns; /* the namespace local name if present */
156 xmlChar *value; /* value when available */
157 void *data; /* data lib or specific pointer */
158 xmlRelaxNGDefinePtr content; /* the expected content */
159 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
160 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
161 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
162 xmlRelaxNGDefinePtr nameClass; /* the nameClass definition if any */
163 xmlRelaxNGDefinePtr nextHash; /* next define in defs/refs hash tables */
164 short depth; /* used for the cycle detection */
165 short dflags; /* define related flags */
166 xmlRegexpPtr contModel; /* a compiled content model if available */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000167};
168
169/**
170 * _xmlRelaxNG:
171 *
172 * A RelaxNGs definition
173 */
174struct _xmlRelaxNG {
Daniel Veillard4c004142003-10-07 11:33:24 +0000175 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000176 xmlRelaxNGGrammarPtr topgrammar;
177 xmlDocPtr doc;
178
Daniel Veillard4c004142003-10-07 11:33:24 +0000179 int idref; /* requires idref checking */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000180
Daniel Veillard4c004142003-10-07 11:33:24 +0000181 xmlHashTablePtr defs; /* define */
182 xmlHashTablePtr refs; /* references */
183 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
184 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
185 int defNr; /* number of defines used */
186 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000187
Daniel Veillard6eadf632003-01-23 18:29:16 +0000188};
189
Daniel Veillard77648bb2003-02-20 15:03:22 +0000190#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
191#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
192#define XML_RELAXNG_IN_LIST (1 << 2)
193#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
194#define XML_RELAXNG_IN_START (1 << 4)
195#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
196#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
197#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000198#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
199#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000200
201struct _xmlRelaxNGParserCtxt {
Daniel Veillard4c004142003-10-07 11:33:24 +0000202 void *userData; /* user specific data block */
203 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
204 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000205 xmlStructuredErrorFunc serror;
Daniel Veillard42f12e92003-03-07 18:32:59 +0000206 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000207
Daniel Veillard4c004142003-10-07 11:33:24 +0000208 xmlRelaxNGPtr schema; /* The schema in use */
209 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
210 xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */
211 int flags; /* parser flags */
212 int nbErrors; /* number of errors at parse time */
213 int nbWarnings; /* number of warnings at parse time */
214 const xmlChar *define; /* the current define scope */
215 xmlRelaxNGDefinePtr def; /* the current define */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000216
Daniel Veillard4c004142003-10-07 11:33:24 +0000217 int nbInterleaves;
218 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000219
Daniel Veillard4c004142003-10-07 11:33:24 +0000220 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
221 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
222 xmlChar *URL;
223 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000224
Daniel Veillard4c004142003-10-07 11:33:24 +0000225 int defNr; /* number of defines used */
226 int defMax; /* number of defines aloocated */
227 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
Daniel Veillard419a7682003-02-03 23:22:49 +0000228
Daniel Veillard4c004142003-10-07 11:33:24 +0000229 const char *buffer;
230 int size;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000231
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000232 /* the document stack */
Daniel Veillard4c004142003-10-07 11:33:24 +0000233 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
234 int docNr; /* Depth of the parsing stack */
235 int docMax; /* Max depth of the parsing stack */
236 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000237
238 /* the include stack */
Daniel Veillard4c004142003-10-07 11:33:24 +0000239 xmlRelaxNGIncludePtr inc; /* Current parsed include */
240 int incNr; /* Depth of the include parsing stack */
241 int incMax; /* Max depth of the parsing stack */
242 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000243
Daniel Veillard4c004142003-10-07 11:33:24 +0000244 int idref; /* requires idref checking */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000245
246 /* used to compile content models */
Daniel Veillard4c004142003-10-07 11:33:24 +0000247 xmlAutomataPtr am; /* the automata */
248 xmlAutomataStatePtr state; /* used to build the automata */
Daniel Veillard03c2f0a2004-01-25 19:54:59 +0000249
250 int crng; /* compact syntax and other flags */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000251};
252
253#define FLAGS_IGNORABLE 1
254#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000255#define FLAGS_MIXED_CONTENT 4
Daniel Veillard6eadf632003-01-23 18:29:16 +0000256
257/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000258 * xmlRelaxNGInterleaveGroup:
259 *
260 * A RelaxNGs partition set associated to lists of definitions
261 */
262typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
263typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
264struct _xmlRelaxNGInterleaveGroup {
Daniel Veillard4c004142003-10-07 11:33:24 +0000265 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
266 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
267 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000268};
269
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000270#define IS_DETERMINIST 1
271#define IS_NEEDCHECK 2
Daniel Veillard4c004142003-10-07 11:33:24 +0000272
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000273/**
274 * xmlRelaxNGPartitions:
275 *
276 * A RelaxNGs partition associated to an interleave group
277 */
278typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
279typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
280struct _xmlRelaxNGPartition {
Daniel Veillard4c004142003-10-07 11:33:24 +0000281 int nbgroups; /* number of groups in the partitions */
282 xmlHashTablePtr triage; /* hash table used to direct nodes to the
283 * right group when possible */
284 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000285 xmlRelaxNGInterleaveGroupPtr *groups;
286};
287
288/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000289 * xmlRelaxNGValidState:
290 *
291 * A RelaxNGs validation state
292 */
293#define MAX_ATTR 20
294typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
295typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
296struct _xmlRelaxNGValidState {
Daniel Veillard4c004142003-10-07 11:33:24 +0000297 xmlNodePtr node; /* the current node */
298 xmlNodePtr seq; /* the sequence of children left to validate */
299 int nbAttrs; /* the number of attributes */
300 int maxAttrs; /* the size of attrs */
301 int nbAttrLeft; /* the number of attributes left to validate */
302 xmlChar *value; /* the value when operating on string */
303 xmlChar *endvalue; /* the end value when operating on string */
304 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000305};
306
307/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000308 * xmlRelaxNGStates:
309 *
310 * A RelaxNGs container for validation state
311 */
312typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
313typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
314struct _xmlRelaxNGStates {
Daniel Veillard4c004142003-10-07 11:33:24 +0000315 int nbState; /* the number of states */
316 int maxState; /* the size of the array */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000317 xmlRelaxNGValidStatePtr *tabState;
318};
319
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000320#define ERROR_IS_DUP 1
Daniel Veillard4c004142003-10-07 11:33:24 +0000321
Daniel Veillardfd573f12003-03-16 17:52:32 +0000322/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000323 * xmlRelaxNGValidError:
324 *
325 * A RelaxNGs validation error
326 */
327typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
328typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
329struct _xmlRelaxNGValidError {
Daniel Veillard4c004142003-10-07 11:33:24 +0000330 xmlRelaxNGValidErr err; /* the error number */
331 int flags; /* flags */
332 xmlNodePtr node; /* the current node */
333 xmlNodePtr seq; /* the current child */
334 const xmlChar *arg1; /* first arg */
335 const xmlChar *arg2; /* second arg */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000336};
337
338/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000339 * xmlRelaxNGValidCtxt:
340 *
341 * A RelaxNGs validation context
342 */
343
344struct _xmlRelaxNGValidCtxt {
Daniel Veillard4c004142003-10-07 11:33:24 +0000345 void *userData; /* user specific data block */
346 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
347 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000348 xmlStructuredErrorFunc serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000349 int nbErrors; /* number of errors in validation */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000350
Daniel Veillard4c004142003-10-07 11:33:24 +0000351 xmlRelaxNGPtr schema; /* The schema in use */
352 xmlDocPtr doc; /* the document being validated */
353 int flags; /* validation flags */
354 int depth; /* validation depth */
355 int idref; /* requires idref checking */
356 int errNo; /* the first error found */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000357
358 /*
359 * Errors accumulated in branches may have to be stacked to be
360 * provided back when it's sure they affect validation.
361 */
362 xmlRelaxNGValidErrorPtr err; /* Last error */
Daniel Veillard4c004142003-10-07 11:33:24 +0000363 int errNr; /* Depth of the error stack */
364 int errMax; /* Max depth of the error stack */
365 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000366
Daniel Veillard4c004142003-10-07 11:33:24 +0000367 xmlRelaxNGValidStatePtr state; /* the current validation state */
368 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000369
Daniel Veillard4c004142003-10-07 11:33:24 +0000370 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
371 int freeStatesNr;
372 int freeStatesMax;
373 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillardf4e55762003-04-15 23:32:22 +0000374
375 /*
376 * This is used for "progressive" validation
377 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000378 xmlRegExecCtxtPtr elem; /* the current element regexp */
379 int elemNr; /* the number of element validated */
380 int elemMax; /* the max depth of elements */
381 xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
382 int pstate; /* progressive state */
383 xmlNodePtr pnode; /* the current node */
384 xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */
385 int perr; /* signal error in content model
386 * outside the regexp */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000387};
388
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000389/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000390 * xmlRelaxNGInclude:
391 *
392 * Structure associated to a RelaxNGs document element
393 */
394struct _xmlRelaxNGInclude {
Daniel Veillard4c004142003-10-07 11:33:24 +0000395 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
396 xmlChar *href; /* the normalized href value */
397 xmlDocPtr doc; /* the associated XML document */
398 xmlRelaxNGDefinePtr content; /* the definitions */
399 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000400};
401
402/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000403 * xmlRelaxNGDocument:
404 *
405 * Structure associated to a RelaxNGs document element
406 */
407struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000408 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillard4c004142003-10-07 11:33:24 +0000409 xmlChar *href; /* the normalized href value */
410 xmlDocPtr doc; /* the associated XML document */
411 xmlRelaxNGDefinePtr content; /* the definitions */
412 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000413};
414
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000415
Daniel Veillard6eadf632003-01-23 18:29:16 +0000416/************************************************************************
Daniel Veillard4c004142003-10-07 11:33:24 +0000417 * *
418 * Some factorized error routines *
419 * *
420 ************************************************************************/
421
422/**
423 * xmlRngPErrMemory:
424 * @ctxt: an Relax-NG parser context
425 * @extra: extra informations
426 *
427 * Handle a redefinition of attribute error
428 */
429static void
430xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
431{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000432 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000433 xmlGenericErrorFunc channel = NULL;
434 void *data = NULL;
435
436 if (ctxt != NULL) {
437 channel = ctxt->error;
438 data = ctxt->userData;
439 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000440 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000441 }
442 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000443 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000444 NULL, NULL, XML_FROM_RELAXNGP,
445 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
446 NULL, NULL, 0, 0,
447 "Memory allocation failed : %s\n", extra);
448 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000449 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000450 NULL, NULL, XML_FROM_RELAXNGP,
451 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
452 NULL, NULL, 0, 0, "Memory allocation failed\n");
453}
454
455/**
456 * xmlRngVErrMemory:
457 * @ctxt: a Relax-NG validation context
458 * @extra: extra informations
459 *
460 * Handle a redefinition of attribute error
461 */
462static void
463xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
464{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000465 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000466 xmlGenericErrorFunc channel = NULL;
467 void *data = NULL;
468
469 if (ctxt != NULL) {
470 channel = ctxt->error;
471 data = ctxt->userData;
472 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000473 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000474 }
475 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000476 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000477 NULL, NULL, XML_FROM_RELAXNGV,
478 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
479 NULL, NULL, 0, 0,
480 "Memory allocation failed : %s\n", extra);
481 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000482 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000483 NULL, NULL, XML_FROM_RELAXNGV,
484 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
485 NULL, NULL, 0, 0, "Memory allocation failed\n");
486}
487
488/**
489 * xmlRngPErr:
490 * @ctxt: a Relax-NG parser context
491 * @node: the node raising the error
492 * @error: the error code
493 * @msg: message
494 * @str1: extra info
495 * @str2: extra info
496 *
497 * Handle a Relax NG Parsing error
498 */
499static void
500xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
501 const char *msg, const xmlChar * str1, const xmlChar * str2)
502{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000503 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000504 xmlGenericErrorFunc channel = NULL;
505 void *data = NULL;
506
507 if (ctxt != NULL) {
508 channel = ctxt->error;
509 data = ctxt->userData;
510 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000511 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000512 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000513 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000514 NULL, node, XML_FROM_RELAXNGP,
515 error, XML_ERR_ERROR, NULL, 0,
516 (const char *) str1, (const char *) str2, NULL, 0, 0,
517 msg, str1, str2);
518}
519
520/**
521 * xmlRngVErr:
522 * @ctxt: a Relax-NG validation context
523 * @node: the node raising the error
524 * @error: the error code
525 * @msg: message
526 * @str1: extra info
527 * @str2: extra info
528 *
529 * Handle a Relax NG Validation error
530 */
531static void
532xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
533 const char *msg, const xmlChar * str1, const xmlChar * str2)
534{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000535 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000536 xmlGenericErrorFunc channel = NULL;
537 void *data = NULL;
538
539 if (ctxt != NULL) {
540 channel = ctxt->error;
541 data = ctxt->userData;
542 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000543 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000544 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000545 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000546 NULL, node, XML_FROM_RELAXNGV,
547 error, XML_ERR_ERROR, NULL, 0,
548 (const char *) str1, (const char *) str2, NULL, 0, 0,
549 msg, str1, str2);
550}
551
552/************************************************************************
Daniel Veillard6eadf632003-01-23 18:29:16 +0000553 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000554 * Preliminary type checking interfaces *
555 * *
556 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +0000557
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000558/**
559 * xmlRelaxNGTypeHave:
560 * @data: data needed for the library
561 * @type: the type name
562 * @value: the value to check
563 *
564 * Function provided by a type library to check if a type is exported
565 *
566 * Returns 1 if yes, 0 if no and -1 in case of error.
567 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000568typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000569
570/**
571 * xmlRelaxNGTypeCheck:
572 * @data: data needed for the library
573 * @type: the type name
574 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000575 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000576 *
577 * Function provided by a type library to check if a value match a type
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 (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
582 const xmlChar * value, void **result,
583 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000584
585/**
586 * xmlRelaxNGFacetCheck:
587 * @data: data needed for the library
588 * @type: the type name
589 * @facet: the facet name
590 * @val: the facet value
591 * @strval: the string value
592 * @value: the value to check
593 *
594 * Function provided by a type library to check a value facet
595 *
596 * Returns 1 if yes, 0 if no and -1 in case of error.
597 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000598typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
599 const xmlChar * facet,
600 const xmlChar * val,
601 const xmlChar * strval, void *value);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000602
603/**
604 * xmlRelaxNGTypeFree:
605 * @data: data needed for the library
606 * @result: the value to free
607 *
608 * Function provided by a type library to free a returned result
609 */
610typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000611
612/**
613 * xmlRelaxNGTypeCompare:
614 * @data: data needed for the library
615 * @type: the type name
616 * @value1: the first value
617 * @value2: the second value
618 *
619 * Function provided by a type library to compare two values accordingly
620 * to a type.
621 *
622 * Returns 1 if yes, 0 if no and -1 in case of error.
623 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000624typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
625 const xmlChar * value1,
626 xmlNodePtr ctxt1,
627 void *comp1,
628 const xmlChar * value2,
629 xmlNodePtr ctxt2);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000630typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
631typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
632struct _xmlRelaxNGTypeLibrary {
Daniel Veillard4c004142003-10-07 11:33:24 +0000633 const xmlChar *namespace; /* the datatypeLibrary value */
634 void *data; /* data needed for the library */
635 xmlRelaxNGTypeHave have; /* the export function */
636 xmlRelaxNGTypeCheck check; /* the checking function */
637 xmlRelaxNGTypeCompare comp; /* the compare function */
638 xmlRelaxNGFacetCheck facet; /* the facet check function */
639 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000640};
641
642/************************************************************************
643 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000644 * Allocation functions *
645 * *
646 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000647static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
648static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillard4c004142003-10-07 11:33:24 +0000649static void xmlRelaxNGNormExtSpace(xmlChar * value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000650static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillard4c004142003-10-07 11:33:24 +0000651static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
652 ATTRIBUTE_UNUSED,
653 xmlRelaxNGValidStatePtr state1,
654 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000655static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +0000656 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000657
658/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000659 * xmlRelaxNGFreeDocument:
660 * @docu: a document structure
661 *
662 * Deallocate a RelaxNG document structure.
663 */
664static void
665xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
666{
667 if (docu == NULL)
668 return;
669
670 if (docu->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000671 xmlFree(docu->href);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000672 if (docu->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000673 xmlFreeDoc(docu->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000674 if (docu->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000675 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000676 xmlFree(docu);
677}
678
679/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000680 * xmlRelaxNGFreeDocumentList:
681 * @docu: a list of document structure
682 *
683 * Deallocate a RelaxNG document structures.
684 */
685static void
686xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
687{
688 xmlRelaxNGDocumentPtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000689
Daniel Veillardc482e262003-02-26 14:48:48 +0000690 while (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000691 next = docu->next;
692 xmlRelaxNGFreeDocument(docu);
693 docu = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000694 }
695}
696
697/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000698 * xmlRelaxNGFreeInclude:
699 * @incl: a include structure
700 *
701 * Deallocate a RelaxNG include structure.
702 */
703static void
704xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
705{
706 if (incl == NULL)
707 return;
708
709 if (incl->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000710 xmlFree(incl->href);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000711 if (incl->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000712 xmlFreeDoc(incl->doc);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000713 if (incl->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000714 xmlRelaxNGFree(incl->schema);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000715 xmlFree(incl);
716}
717
718/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000719 * xmlRelaxNGFreeIncludeList:
720 * @incl: a include structure list
721 *
722 * Deallocate a RelaxNG include structure.
723 */
724static void
725xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
726{
727 xmlRelaxNGIncludePtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000728
Daniel Veillardc482e262003-02-26 14:48:48 +0000729 while (incl != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000730 next = incl->next;
731 xmlRelaxNGFreeInclude(incl);
732 incl = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000733 }
734}
735
736/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000737 * xmlRelaxNGNewRelaxNG:
738 * @ctxt: a Relax-NG validation context (optional)
739 *
740 * Allocate a new RelaxNG structure.
741 *
742 * Returns the newly allocated structure or NULL in case or error
743 */
744static xmlRelaxNGPtr
745xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
746{
747 xmlRelaxNGPtr ret;
748
749 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
750 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000751 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000752 return (NULL);
753 }
754 memset(ret, 0, sizeof(xmlRelaxNG));
755
756 return (ret);
757}
758
759/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000760 * xmlRelaxNGFreeInnerSchema:
761 * @schema: a schema structure
762 *
763 * Deallocate a RelaxNG schema structure.
764 */
765static void
766xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
767{
768 if (schema == NULL)
769 return;
770
771 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000772 xmlFreeDoc(schema->doc);
Daniel Veillardc482e262003-02-26 14:48:48 +0000773 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000774 int i;
Daniel Veillardc482e262003-02-26 14:48:48 +0000775
Daniel Veillard4c004142003-10-07 11:33:24 +0000776 for (i = 0; i < schema->defNr; i++)
777 xmlRelaxNGFreeDefine(schema->defTab[i]);
778 xmlFree(schema->defTab);
Daniel Veillardc482e262003-02-26 14:48:48 +0000779 }
780
781 xmlFree(schema);
782}
783
784/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000785 * xmlRelaxNGFree:
786 * @schema: a schema structure
787 *
788 * Deallocate a RelaxNG structure.
789 */
790void
791xmlRelaxNGFree(xmlRelaxNGPtr schema)
792{
793 if (schema == NULL)
794 return;
795
Daniel Veillard6eadf632003-01-23 18:29:16 +0000796 if (schema->topgrammar != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000797 xmlRelaxNGFreeGrammar(schema->topgrammar);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000798 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000799 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000800 if (schema->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000801 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000802 if (schema->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000803 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000804 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000805 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +0000806
Daniel Veillard4c004142003-10-07 11:33:24 +0000807 for (i = 0; i < schema->defNr; i++)
808 xmlRelaxNGFreeDefine(schema->defTab[i]);
809 xmlFree(schema->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +0000810 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000811
812 xmlFree(schema);
813}
814
815/**
816 * xmlRelaxNGNewGrammar:
817 * @ctxt: a Relax-NG validation context (optional)
818 *
819 * Allocate a new RelaxNG grammar.
820 *
821 * Returns the newly allocated structure or NULL in case or error
822 */
823static xmlRelaxNGGrammarPtr
824xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
825{
826 xmlRelaxNGGrammarPtr ret;
827
828 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
829 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000830 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000831 return (NULL);
832 }
833 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
834
835 return (ret);
836}
837
838/**
839 * xmlRelaxNGFreeGrammar:
840 * @grammar: a grammar structure
841 *
842 * Deallocate a RelaxNG grammar structure.
843 */
844static void
845xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
846{
847 if (grammar == NULL)
848 return;
849
Daniel Veillardc482e262003-02-26 14:48:48 +0000850 if (grammar->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000851 xmlRelaxNGFreeGrammar(grammar->children);
Daniel Veillardc482e262003-02-26 14:48:48 +0000852 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000853 if (grammar->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000854 xmlRelaxNGFreeGrammar(grammar->next);
Daniel Veillard419a7682003-02-03 23:22:49 +0000855 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000856 if (grammar->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000857 xmlHashFree(grammar->refs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000858 }
859 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000860 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000861 }
862
863 xmlFree(grammar);
864}
865
866/**
867 * xmlRelaxNGNewDefine:
868 * @ctxt: a Relax-NG validation context
869 * @node: the node in the input document.
870 *
871 * Allocate a new RelaxNG define.
872 *
873 * Returns the newly allocated structure or NULL in case or error
874 */
875static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000876xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000877{
878 xmlRelaxNGDefinePtr ret;
879
Daniel Veillard419a7682003-02-03 23:22:49 +0000880 if (ctxt->defMax == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000881 ctxt->defMax = 16;
882 ctxt->defNr = 0;
883 ctxt->defTab = (xmlRelaxNGDefinePtr *)
884 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
885 if (ctxt->defTab == NULL) {
886 xmlRngPErrMemory(ctxt, "allocating define\n");
887 return (NULL);
888 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000889 } else if (ctxt->defMax <= ctxt->defNr) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000890 xmlRelaxNGDefinePtr *tmp;
891
892 ctxt->defMax *= 2;
893 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
894 ctxt->defMax *
895 sizeof
896 (xmlRelaxNGDefinePtr));
897 if (tmp == NULL) {
898 xmlRngPErrMemory(ctxt, "allocating define\n");
899 return (NULL);
900 }
901 ctxt->defTab = tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +0000902 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000903 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
904 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000905 xmlRngPErrMemory(ctxt, "allocating define\n");
906 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000907 }
908 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000909 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000910 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000911 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000912 return (ret);
913}
914
915/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000916 * xmlRelaxNGFreePartition:
917 * @partitions: a partition set structure
918 *
919 * Deallocate RelaxNG partition set structures.
920 */
921static void
Daniel Veillard4c004142003-10-07 11:33:24 +0000922xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
923{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000924 xmlRelaxNGInterleaveGroupPtr group;
925 int j;
926
927 if (partitions != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000928 if (partitions->groups != NULL) {
929 for (j = 0; j < partitions->nbgroups; j++) {
930 group = partitions->groups[j];
931 if (group != NULL) {
932 if (group->defs != NULL)
933 xmlFree(group->defs);
934 if (group->attrs != NULL)
935 xmlFree(group->attrs);
936 xmlFree(group);
937 }
938 }
939 xmlFree(partitions->groups);
940 }
941 if (partitions->triage != NULL) {
942 xmlHashFree(partitions->triage, NULL);
943 }
944 xmlFree(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000945 }
946}
Daniel Veillard4c004142003-10-07 11:33:24 +0000947
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000948/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000949 * xmlRelaxNGFreeDefine:
950 * @define: a define structure
951 *
952 * Deallocate a RelaxNG define structure.
953 */
954static void
955xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
956{
957 if (define == NULL)
958 return;
959
Daniel Veillard4c004142003-10-07 11:33:24 +0000960 if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
961 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000962
Daniel Veillard4c004142003-10-07 11:33:24 +0000963 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
964 if ((lib != NULL) && (lib->freef != NULL))
965 lib->freef(lib->data, (void *) define->attrs);
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000966 }
Daniel Veillard4c004142003-10-07 11:33:24 +0000967 if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
968 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
969 if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
970 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000971 if (define->name != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000972 xmlFree(define->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000973 if (define->ns != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000974 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000975 if (define->value != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000976 xmlFree(define->value);
Daniel Veillard52b48c72003-04-13 19:53:42 +0000977 if (define->contModel != NULL)
978 xmlRegFreeRegexp(define->contModel);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000979 xmlFree(define);
980}
981
982/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000983 * xmlRelaxNGNewStates:
984 * @ctxt: a Relax-NG validation context
985 * @size: the default size for the container
986 *
987 * Allocate a new RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000988 *
989 * Returns the newly allocated structure or NULL in case or error
990 */
991static xmlRelaxNGStatesPtr
992xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
993{
994 xmlRelaxNGStatesPtr ret;
995
Daniel Veillard798024a2003-03-19 10:36:09 +0000996 if ((ctxt != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +0000997 (ctxt->freeState != NULL) && (ctxt->freeStatesNr > 0)) {
998 ctxt->freeStatesNr--;
999 ret = ctxt->freeStates[ctxt->freeStatesNr];
1000 ret->nbState = 0;
1001 return (ret);
Daniel Veillard798024a2003-03-19 10:36:09 +00001002 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001003 if (size < 16)
1004 size = 16;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001005
1006 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
Daniel Veillard4c004142003-10-07 11:33:24 +00001007 (size -
1008 1) *
1009 sizeof(xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001010 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001011 xmlRngVErrMemory(ctxt, "allocating states\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001012 return (NULL);
1013 }
1014 ret->nbState = 0;
1015 ret->maxState = size;
Daniel Veillard4c004142003-10-07 11:33:24 +00001016 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
1017 sizeof
1018 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001019 if (ret->tabState == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001020 xmlRngVErrMemory(ctxt, "allocating states\n");
1021 xmlFree(ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001022 return (NULL);
1023 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001024 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001025}
1026
1027/**
Daniel Veillard798024a2003-03-19 10:36:09 +00001028 * xmlRelaxNGAddStateUniq:
1029 * @ctxt: a Relax-NG validation context
1030 * @states: the states container
1031 * @state: the validation state
1032 *
1033 * Add a RelaxNG validation state to the container without checking
1034 * for unicity.
1035 *
1036 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1037 */
1038static int
1039xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001040 xmlRelaxNGStatesPtr states,
1041 xmlRelaxNGValidStatePtr state)
Daniel Veillard798024a2003-03-19 10:36:09 +00001042{
1043 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001044 return (-1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001045 }
1046 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001047 xmlRelaxNGValidStatePtr *tmp;
1048 int size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001049
Daniel Veillard4c004142003-10-07 11:33:24 +00001050 size = states->maxState * 2;
1051 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1052 (size) *
1053 sizeof
1054 (xmlRelaxNGValidStatePtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001055 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001056 xmlRngVErrMemory(ctxt, "adding states\n");
1057 return (-1);
1058 }
1059 states->tabState = tmp;
1060 states->maxState = size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001061 }
1062 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001063 return (1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001064}
1065
1066/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001067 * xmlRelaxNGAddState:
1068 * @ctxt: a Relax-NG validation context
1069 * @states: the states container
1070 * @state: the validation state
1071 *
1072 * Add a RelaxNG validation state to the container
1073 *
1074 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1075 */
1076static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001077xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
1078 xmlRelaxNGStatesPtr states,
1079 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001080{
1081 int i;
1082
1083 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001084 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001085 }
1086 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001087 xmlRelaxNGValidStatePtr *tmp;
1088 int size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001089
Daniel Veillard4c004142003-10-07 11:33:24 +00001090 size = states->maxState * 2;
1091 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1092 (size) *
1093 sizeof
1094 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001095 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001096 xmlRngVErrMemory(ctxt, "adding states\n");
1097 return (-1);
1098 }
1099 states->tabState = tmp;
1100 states->maxState = size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001101 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001102 for (i = 0; i < states->nbState; i++) {
1103 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
1104 xmlRelaxNGFreeValidState(ctxt, state);
1105 return (0);
1106 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001107 }
1108 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001109 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001110}
1111
1112/**
1113 * xmlRelaxNGFreeStates:
1114 * @ctxt: a Relax-NG validation context
1115 * @states: teh container
1116 *
1117 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +00001118 */
1119static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001120xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001121 xmlRelaxNGStatesPtr states)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001122{
Daniel Veillard798024a2003-03-19 10:36:09 +00001123 if (states == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001124 return;
Daniel Veillard798024a2003-03-19 10:36:09 +00001125 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001126 ctxt->freeStatesMax = 40;
1127 ctxt->freeStatesNr = 0;
1128 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
1129 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
1130 if (ctxt->freeStates == NULL) {
1131 xmlRngVErrMemory(ctxt, "storing states\n");
1132 }
1133 } else if ((ctxt != NULL)
1134 && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
1135 xmlRelaxNGStatesPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001136
Daniel Veillard4c004142003-10-07 11:33:24 +00001137 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
1138 2 * ctxt->freeStatesMax *
1139 sizeof
1140 (xmlRelaxNGStatesPtr));
1141 if (tmp == NULL) {
1142 xmlRngVErrMemory(ctxt, "storing states\n");
1143 xmlFree(states->tabState);
1144 xmlFree(states);
1145 return;
1146 }
1147 ctxt->freeStates = tmp;
1148 ctxt->freeStatesMax *= 2;
Daniel Veillard798024a2003-03-19 10:36:09 +00001149 }
1150 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001151 xmlFree(states->tabState);
1152 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +00001153 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001154 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001155 }
1156}
1157
1158/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001159 * xmlRelaxNGNewValidState:
1160 * @ctxt: a Relax-NG validation context
1161 * @node: the current node or NULL for the document
1162 *
1163 * Allocate a new RelaxNG validation state
1164 *
1165 * Returns the newly allocated structure or NULL in case or error
1166 */
1167static xmlRelaxNGValidStatePtr
1168xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1169{
1170 xmlRelaxNGValidStatePtr ret;
1171 xmlAttrPtr attr;
1172 xmlAttrPtr attrs[MAX_ATTR];
1173 int nbAttrs = 0;
1174 xmlNodePtr root = NULL;
1175
1176 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001177 root = xmlDocGetRootElement(ctxt->doc);
1178 if (root == NULL)
1179 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001180 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001181 attr = node->properties;
1182 while (attr != NULL) {
1183 if (nbAttrs < MAX_ATTR)
1184 attrs[nbAttrs++] = attr;
1185 else
1186 nbAttrs++;
1187 attr = attr->next;
1188 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001189 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001190 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1191 ctxt->freeState->nbState--;
1192 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001193 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001194 ret =
1195 (xmlRelaxNGValidStatePtr)
1196 xmlMalloc(sizeof(xmlRelaxNGValidState));
1197 if (ret == NULL) {
1198 xmlRngVErrMemory(ctxt, "allocating states\n");
1199 return (NULL);
1200 }
1201 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001202 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001203 ret->value = NULL;
1204 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001205 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001206 ret->node = (xmlNodePtr) ctxt->doc;
1207 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001208 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001209 ret->node = node;
1210 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001211 }
1212 ret->nbAttrs = 0;
1213 if (nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001214 if (ret->attrs == NULL) {
1215 if (nbAttrs < 4)
1216 ret->maxAttrs = 4;
1217 else
1218 ret->maxAttrs = nbAttrs;
1219 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1220 sizeof(xmlAttrPtr));
1221 if (ret->attrs == NULL) {
1222 xmlRngVErrMemory(ctxt, "allocating states\n");
1223 return (ret);
1224 }
1225 } else if (ret->maxAttrs < nbAttrs) {
1226 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001227
Daniel Veillard4c004142003-10-07 11:33:24 +00001228 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1229 sizeof(xmlAttrPtr));
1230 if (tmp == NULL) {
1231 xmlRngVErrMemory(ctxt, "allocating states\n");
1232 return (ret);
1233 }
1234 ret->attrs = tmp;
1235 ret->maxAttrs = nbAttrs;
1236 }
1237 ret->nbAttrs = nbAttrs;
1238 if (nbAttrs < MAX_ATTR) {
1239 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1240 } else {
1241 attr = node->properties;
1242 nbAttrs = 0;
1243 while (attr != NULL) {
1244 ret->attrs[nbAttrs++] = attr;
1245 attr = attr->next;
1246 }
1247 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001248 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001249 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001250 return (ret);
1251}
1252
1253/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001254 * xmlRelaxNGCopyValidState:
1255 * @ctxt: a Relax-NG validation context
1256 * @state: a validation state
1257 *
1258 * Copy the validation state
1259 *
1260 * Returns the newly allocated structure or NULL in case or error
1261 */
1262static xmlRelaxNGValidStatePtr
1263xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001264 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001265{
1266 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001267 unsigned int maxAttrs;
1268 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001269
1270 if (state == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001271 return (NULL);
1272 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1273 ctxt->freeState->nbState--;
1274 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001275 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001276 ret =
1277 (xmlRelaxNGValidStatePtr)
1278 xmlMalloc(sizeof(xmlRelaxNGValidState));
1279 if (ret == NULL) {
1280 xmlRngVErrMemory(ctxt, "allocating states\n");
1281 return (NULL);
1282 }
1283 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001284 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001285 attrs = ret->attrs;
1286 maxAttrs = ret->maxAttrs;
1287 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1288 ret->attrs = attrs;
1289 ret->maxAttrs = maxAttrs;
1290 if (state->nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001291 if (ret->attrs == NULL) {
1292 ret->maxAttrs = state->maxAttrs;
1293 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1294 sizeof(xmlAttrPtr));
1295 if (ret->attrs == NULL) {
1296 xmlRngVErrMemory(ctxt, "allocating states\n");
1297 ret->nbAttrs = 0;
1298 return (ret);
1299 }
1300 } else if (ret->maxAttrs < state->nbAttrs) {
1301 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001302
Daniel Veillard4c004142003-10-07 11:33:24 +00001303 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1304 sizeof(xmlAttrPtr));
1305 if (tmp == NULL) {
1306 xmlRngVErrMemory(ctxt, "allocating states\n");
1307 ret->nbAttrs = 0;
1308 return (ret);
1309 }
1310 ret->maxAttrs = state->maxAttrs;
1311 ret->attrs = tmp;
1312 }
1313 memcpy(ret->attrs, state->attrs,
1314 state->nbAttrs * sizeof(xmlAttrPtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001315 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001316 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001317}
1318
1319/**
1320 * xmlRelaxNGEqualValidState:
1321 * @ctxt: a Relax-NG validation context
1322 * @state1: a validation state
1323 * @state2: a validation state
1324 *
1325 * Compare the validation states for equality
1326 *
1327 * Returns 1 if equald, 0 otherwise
1328 */
1329static int
1330xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00001331 xmlRelaxNGValidStatePtr state1,
1332 xmlRelaxNGValidStatePtr state2)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001333{
1334 int i;
1335
1336 if ((state1 == NULL) || (state2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00001337 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001338 if (state1 == state2)
Daniel Veillard4c004142003-10-07 11:33:24 +00001339 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001340 if (state1->node != state2->node)
Daniel Veillard4c004142003-10-07 11:33:24 +00001341 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001342 if (state1->seq != state2->seq)
Daniel Veillard4c004142003-10-07 11:33:24 +00001343 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001344 if (state1->nbAttrLeft != state2->nbAttrLeft)
Daniel Veillard4c004142003-10-07 11:33:24 +00001345 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001346 if (state1->nbAttrs != state2->nbAttrs)
Daniel Veillard4c004142003-10-07 11:33:24 +00001347 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001348 if (state1->endvalue != state2->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00001349 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001350 if ((state1->value != state2->value) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001351 (!xmlStrEqual(state1->value, state2->value)))
1352 return (0);
1353 for (i = 0; i < state1->nbAttrs; i++) {
1354 if (state1->attrs[i] != state2->attrs[i])
1355 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001356 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001357 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001358}
1359
1360/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001361 * xmlRelaxNGFreeValidState:
1362 * @state: a validation state structure
1363 *
1364 * Deallocate a RelaxNG validation state structure.
1365 */
1366static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001367xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001368 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001369{
1370 if (state == NULL)
1371 return;
1372
Daniel Veillard798024a2003-03-19 10:36:09 +00001373 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001374 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
Daniel Veillard798024a2003-03-19 10:36:09 +00001375 }
1376 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001377 if (state->attrs != NULL)
1378 xmlFree(state->attrs);
1379 xmlFree(state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001380 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001381 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001382 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001383}
1384
1385/************************************************************************
1386 * *
Daniel Veillard03c2f0a2004-01-25 19:54:59 +00001387 * Semi internal functions *
1388 * *
1389 ************************************************************************/
1390
1391/**
1392 * xmlRelaxParserSetFlag:
1393 * @ctxt: a RelaxNG parser context
1394 * @flags: a set of flags values
1395 *
1396 * Semi private function used to pass informations to a parser context
1397 * which are a combination of xmlRelaxNGParserFlag .
1398 *
1399 * Returns 0 if success and -1 in case of error
1400 */
1401int
1402xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
1403{
1404 if (ctxt == NULL) return(-1);
1405 if (flags & XML_RELAXNGP_FREE_DOC) {
1406 ctxt->crng |= XML_RELAXNGP_FREE_DOC;
1407 flags -= XML_RELAXNGP_FREE_DOC;
1408 }
1409 if (flags & XML_RELAXNGP_CRNG) {
1410 ctxt->crng |= XML_RELAXNGP_CRNG;
1411 flags -= XML_RELAXNGP_CRNG;
1412 }
1413 if (flags != 0) return(-1);
1414 return(0);
1415}
1416
1417/************************************************************************
1418 * *
1419 * Document functions *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001420 * *
1421 ************************************************************************/
1422static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001423 xmlDocPtr doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001424
1425/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001426 * xmlRelaxNGIncludePush:
1427 * @ctxt: the parser context
1428 * @value: the element doc
1429 *
1430 * Pushes a new include on top of the include stack
1431 *
1432 * Returns 0 in case of error, the index in the stack otherwise
1433 */
1434static int
1435xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001436 xmlRelaxNGIncludePtr value)
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001437{
1438 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001439 ctxt->incMax = 4;
1440 ctxt->incNr = 0;
1441 ctxt->incTab =
1442 (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
1443 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001444 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001445 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001446 return (0);
1447 }
1448 }
1449 if (ctxt->incNr >= ctxt->incMax) {
1450 ctxt->incMax *= 2;
1451 ctxt->incTab =
1452 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001453 ctxt->incMax *
1454 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001455 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001456 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001457 return (0);
1458 }
1459 }
1460 ctxt->incTab[ctxt->incNr] = value;
1461 ctxt->inc = value;
1462 return (ctxt->incNr++);
1463}
1464
1465/**
1466 * xmlRelaxNGIncludePop:
1467 * @ctxt: the parser context
1468 *
1469 * Pops the top include from the include stack
1470 *
1471 * Returns the include just removed
1472 */
1473static xmlRelaxNGIncludePtr
1474xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1475{
1476 xmlRelaxNGIncludePtr ret;
1477
1478 if (ctxt->incNr <= 0)
1479 return (0);
1480 ctxt->incNr--;
1481 if (ctxt->incNr > 0)
1482 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1483 else
1484 ctxt->inc = NULL;
1485 ret = ctxt->incTab[ctxt->incNr];
1486 ctxt->incTab[ctxt->incNr] = 0;
1487 return (ret);
1488}
1489
1490/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001491 * xmlRelaxNGRemoveRedefine:
1492 * @ctxt: the parser context
1493 * @URL: the normalized URL
1494 * @target: the included target
1495 * @name: the define name to eliminate
1496 *
1497 * Applies the elimination algorithm of 4.7
1498 *
1499 * Returns 0 in case of error, 1 in case of success.
1500 */
1501static int
1502xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001503 const xmlChar * URL ATTRIBUTE_UNUSED,
1504 xmlNodePtr target, const xmlChar * name)
1505{
Daniel Veillard5add8682003-03-10 13:13:58 +00001506 int found = 0;
1507 xmlNodePtr tmp, tmp2;
1508 xmlChar *name2;
1509
1510#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001511 if (name == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001512 xmlGenericError(xmlGenericErrorContext,
1513 "Elimination of <include> start from %s\n", URL);
Daniel Veillard952379b2003-03-17 15:37:12 +00001514 else
Daniel Veillard4c004142003-10-07 11:33:24 +00001515 xmlGenericError(xmlGenericErrorContext,
1516 "Elimination of <include> define %s from %s\n",
1517 name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001518#endif
1519 tmp = target;
1520 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001521 tmp2 = tmp->next;
1522 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1523 found = 1;
1524 xmlUnlinkNode(tmp);
1525 xmlFreeNode(tmp);
1526 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1527 name2 = xmlGetProp(tmp, BAD_CAST "name");
1528 xmlRelaxNGNormExtSpace(name2);
1529 if (name2 != NULL) {
1530 if (xmlStrEqual(name, name2)) {
1531 found = 1;
1532 xmlUnlinkNode(tmp);
1533 xmlFreeNode(tmp);
1534 }
1535 xmlFree(name2);
1536 }
1537 } else if (IS_RELAXNG(tmp, "include")) {
1538 xmlChar *href = NULL;
Daniel Veillard807daf82004-02-22 22:13:27 +00001539 xmlRelaxNGDocumentPtr inc = tmp->psvi;
Daniel Veillard5add8682003-03-10 13:13:58 +00001540
Daniel Veillard4c004142003-10-07 11:33:24 +00001541 if ((inc != NULL) && (inc->doc != NULL) &&
1542 (inc->doc->children != NULL)) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001543
Daniel Veillard4c004142003-10-07 11:33:24 +00001544 if (xmlStrEqual
1545 (inc->doc->children->name, BAD_CAST "grammar")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001546#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001547 href = xmlGetProp(tmp, BAD_CAST "href");
Daniel Veillard5add8682003-03-10 13:13:58 +00001548#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00001549 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1550 inc->doc->children->
1551 children, name) == 1) {
1552 found = 1;
1553 }
1554 if (href != NULL)
1555 xmlFree(href);
1556 }
1557 }
1558 }
1559 tmp = tmp2;
Daniel Veillard5add8682003-03-10 13:13:58 +00001560 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001561 return (found);
Daniel Veillard5add8682003-03-10 13:13:58 +00001562}
1563
1564/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001565 * xmlRelaxNGLoadInclude:
1566 * @ctxt: the parser context
1567 * @URL: the normalized URL
1568 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001569 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001570 *
1571 * First lookup if the document is already loaded into the parser context,
1572 * check against recursion. If not found the resource is loaded and
1573 * the content is preprocessed before being returned back to the caller.
1574 *
1575 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1576 */
1577static xmlRelaxNGIncludePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001578xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
1579 xmlNodePtr node, const xmlChar * ns)
1580{
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001581 xmlRelaxNGIncludePtr ret = NULL;
1582 xmlDocPtr doc;
1583 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001584 xmlNodePtr root, cur;
1585
1586#ifdef DEBUG_INCLUDE
1587 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001588 "xmlRelaxNGLoadInclude(%s)\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001589#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001590
1591 /*
1592 * check against recursion in the stack
1593 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001594 for (i = 0; i < ctxt->incNr; i++) {
1595 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1596 xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
1597 "Detected an Include recursion for %s\n", URL,
1598 NULL);
1599 return (NULL);
1600 }
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001601 }
1602
1603 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001604 * load the document
1605 */
Daniel Veillard87247e82004-01-13 20:42:02 +00001606 doc = xmlReadFile((const char *) URL,NULL,0);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001607 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001608 xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
1609 "xmlRelaxNG: could not load %s\n", URL, NULL);
1610 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001611 }
Daniel Veillard5add8682003-03-10 13:13:58 +00001612#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001613 xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001614#endif
1615
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001616 /*
1617 * Allocate the document structures and register it first.
1618 */
1619 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1620 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001621 xmlRngPErrMemory(ctxt, "allocating include\n");
1622 xmlFreeDoc(doc);
1623 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001624 }
1625 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1626 ret->doc = doc;
1627 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001628 ret->next = ctxt->includes;
1629 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001630
1631 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001632 * transmit the ns if needed
1633 */
1634 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001635 root = xmlDocGetRootElement(doc);
1636 if (root != NULL) {
1637 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1638 xmlSetProp(root, BAD_CAST "ns", ns);
1639 }
1640 }
Daniel Veillard416589a2003-02-17 17:25:42 +00001641 }
1642
1643 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001644 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001645 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001646 xmlRelaxNGIncludePush(ctxt, ret);
1647
1648 /*
1649 * Some preprocessing of the document content, this include recursing
1650 * in the include stack.
1651 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001652#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001653 xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001654#endif
1655
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001656 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1657 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001658 ctxt->inc = NULL;
1659 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001660 }
1661
1662 /*
1663 * Pop up the include from the stack
1664 */
1665 xmlRelaxNGIncludePop(ctxt);
1666
Daniel Veillard5add8682003-03-10 13:13:58 +00001667#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001668 xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001669#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001670 /*
1671 * Check that the top element is a grammar
1672 */
1673 root = xmlDocGetRootElement(doc);
1674 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001675 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
1676 "xmlRelaxNG: included document is empty %s\n", URL,
1677 NULL);
1678 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001679 }
1680 if (!IS_RELAXNG(root, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001681 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
1682 "xmlRelaxNG: included document %s root is not a grammar\n",
1683 URL, NULL);
1684 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001685 }
1686
1687 /*
1688 * Elimination of redefined rules in the include.
1689 */
1690 cur = node->children;
1691 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001692 if (IS_RELAXNG(cur, "start")) {
1693 int found = 0;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001694
Daniel Veillard4c004142003-10-07 11:33:24 +00001695 found =
1696 xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
1697 if (!found) {
1698 xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
1699 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1700 URL, NULL);
1701 }
1702 } else if (IS_RELAXNG(cur, "define")) {
1703 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001704
Daniel Veillard4c004142003-10-07 11:33:24 +00001705 name = xmlGetProp(cur, BAD_CAST "name");
1706 if (name == NULL) {
1707 xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
1708 "xmlRelaxNG: include %s has define without name\n",
1709 URL, NULL);
1710 } else {
1711 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001712
Daniel Veillard4c004142003-10-07 11:33:24 +00001713 xmlRelaxNGNormExtSpace(name);
1714 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1715 root->children, name);
1716 if (!found) {
1717 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
1718 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1719 URL, name);
1720 }
1721 xmlFree(name);
1722 }
1723 }
1724 cur = cur->next;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001725 }
1726
1727
Daniel Veillard4c004142003-10-07 11:33:24 +00001728 return (ret);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001729}
1730
1731/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001732 * xmlRelaxNGValidErrorPush:
1733 * @ctxt: the validation context
1734 * @err: the error code
1735 * @arg1: the first string argument
1736 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001737 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001738 *
1739 * Pushes a new error on top of the error stack
1740 *
1741 * Returns 0 in case of error, the index in the stack otherwise
1742 */
1743static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001744xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
1745 xmlRelaxNGValidErr err, const xmlChar * arg1,
1746 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001747{
1748 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00001749
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001750#ifdef DEBUG_ERROR
1751 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001752 "Pushing error %d at %d on stack\n", err, ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001753#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00001754 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001755 ctxt->errMax = 8;
1756 ctxt->errNr = 0;
1757 ctxt->errTab =
1758 (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
1759 sizeof
1760 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001761 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001762 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001763 return (0);
1764 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001765 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001766 }
1767 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001768 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001769 ctxt->errTab =
1770 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001771 ctxt->errMax *
1772 sizeof
1773 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001774 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001775 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001776 return (0);
1777 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001778 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001779 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001780 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001781 (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
1782 return (ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001783 cur = &ctxt->errTab[ctxt->errNr];
1784 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001785 if (dup) {
1786 cur->arg1 = xmlStrdup(arg1);
1787 cur->arg2 = xmlStrdup(arg2);
Daniel Veillard4c004142003-10-07 11:33:24 +00001788 cur->flags = ERROR_IS_DUP;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001789 } else {
1790 cur->arg1 = arg1;
1791 cur->arg2 = arg2;
Daniel Veillard4c004142003-10-07 11:33:24 +00001792 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001793 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001794 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001795 cur->node = ctxt->state->node;
1796 cur->seq = ctxt->state->seq;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001797 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001798 cur->node = NULL;
1799 cur->seq = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001800 }
1801 ctxt->err = cur;
1802 return (ctxt->errNr++);
1803}
1804
1805/**
1806 * xmlRelaxNGValidErrorPop:
1807 * @ctxt: the validation context
1808 *
1809 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001810 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001811static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001812xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1813{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001814 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001815
Daniel Veillard580ced82003-03-21 21:22:48 +00001816 if (ctxt->errNr <= 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001817 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001818 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001819 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001820 ctxt->errNr--;
1821 if (ctxt->errNr > 0)
1822 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1823 else
1824 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001825 cur = &ctxt->errTab[ctxt->errNr];
1826 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001827 if (cur->arg1 != NULL)
1828 xmlFree((xmlChar *) cur->arg1);
1829 cur->arg1 = NULL;
1830 if (cur->arg2 != NULL)
1831 xmlFree((xmlChar *) cur->arg2);
1832 cur->arg2 = NULL;
1833 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001834 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001835}
1836
Daniel Veillard42f12e92003-03-07 18:32:59 +00001837/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001838 * xmlRelaxNGDocumentPush:
1839 * @ctxt: the parser context
1840 * @value: the element doc
1841 *
1842 * Pushes a new doc on top of the doc stack
1843 *
1844 * Returns 0 in case of error, the index in the stack otherwise
1845 */
1846static int
1847xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001848 xmlRelaxNGDocumentPtr value)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001849{
1850 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001851 ctxt->docMax = 4;
1852 ctxt->docNr = 0;
1853 ctxt->docTab =
1854 (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
1855 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001856 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001857 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001858 return (0);
1859 }
1860 }
1861 if (ctxt->docNr >= ctxt->docMax) {
1862 ctxt->docMax *= 2;
1863 ctxt->docTab =
1864 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001865 ctxt->docMax *
1866 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001867 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001868 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001869 return (0);
1870 }
1871 }
1872 ctxt->docTab[ctxt->docNr] = value;
1873 ctxt->doc = value;
1874 return (ctxt->docNr++);
1875}
1876
1877/**
1878 * xmlRelaxNGDocumentPop:
1879 * @ctxt: the parser context
1880 *
1881 * Pops the top doc from the doc stack
1882 *
1883 * Returns the doc just removed
1884 */
1885static xmlRelaxNGDocumentPtr
1886xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1887{
1888 xmlRelaxNGDocumentPtr ret;
1889
1890 if (ctxt->docNr <= 0)
1891 return (0);
1892 ctxt->docNr--;
1893 if (ctxt->docNr > 0)
1894 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1895 else
1896 ctxt->doc = NULL;
1897 ret = ctxt->docTab[ctxt->docNr];
1898 ctxt->docTab[ctxt->docNr] = 0;
1899 return (ret);
1900}
1901
1902/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001903 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001904 * @ctxt: the parser context
1905 * @URL: the normalized URL
1906 * @ns: the inherited ns if any
1907 *
1908 * First lookup if the document is already loaded into the parser context,
1909 * check against recursion. If not found the resource is loaded and
1910 * the content is preprocessed before being returned back to the caller.
1911 *
1912 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1913 */
1914static xmlRelaxNGDocumentPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001915xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
1916 const xmlChar * URL, const xmlChar * ns)
1917{
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001918 xmlRelaxNGDocumentPtr ret = NULL;
1919 xmlDocPtr doc;
1920 xmlNodePtr root;
1921 int i;
1922
1923 /*
1924 * check against recursion in the stack
1925 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001926 for (i = 0; i < ctxt->docNr; i++) {
1927 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1928 xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
1929 "Detected an externalRef recursion for %s\n", URL,
1930 NULL);
1931 return (NULL);
1932 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001933 }
1934
1935 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001936 * load the document
1937 */
Daniel Veillard87247e82004-01-13 20:42:02 +00001938 doc = xmlReadFile((const char *) URL,NULL,0);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001939 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001940 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
1941 "xmlRelaxNG: could not load %s\n", URL, NULL);
1942 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001943 }
1944
1945 /*
1946 * Allocate the document structures and register it first.
1947 */
1948 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1949 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001950 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
1951 "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
1952 xmlFreeDoc(doc);
1953 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001954 }
1955 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1956 ret->doc = doc;
1957 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001958 ret->next = ctxt->documents;
1959 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001960
1961 /*
1962 * transmit the ns if needed
1963 */
1964 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001965 root = xmlDocGetRootElement(doc);
1966 if (root != NULL) {
1967 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1968 xmlSetProp(root, BAD_CAST "ns", ns);
1969 }
1970 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001971 }
1972
1973 /*
1974 * push it on the stack and register it in the hash table
1975 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001976 xmlRelaxNGDocumentPush(ctxt, ret);
1977
1978 /*
1979 * Some preprocessing of the document content
1980 */
1981 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1982 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001983 ctxt->doc = NULL;
1984 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001985 }
1986
1987 xmlRelaxNGDocumentPop(ctxt);
1988
Daniel Veillard4c004142003-10-07 11:33:24 +00001989 return (ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001990}
1991
1992/************************************************************************
1993 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001994 * Error functions *
1995 * *
1996 ************************************************************************/
1997
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001998#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1999#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2000#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2001#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2002#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002003
Daniel Veillard231d7912003-02-09 14:22:17 +00002004static const char *
Daniel Veillard4c004142003-10-07 11:33:24 +00002005xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
2006{
Daniel Veillard231d7912003-02-09 14:22:17 +00002007 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002008 return ("none");
2009 switch (def->type) {
2010 case XML_RELAXNG_EMPTY:
2011 return ("empty");
2012 case XML_RELAXNG_NOT_ALLOWED:
2013 return ("notAllowed");
2014 case XML_RELAXNG_EXCEPT:
2015 return ("except");
2016 case XML_RELAXNG_TEXT:
2017 return ("text");
2018 case XML_RELAXNG_ELEMENT:
2019 return ("element");
2020 case XML_RELAXNG_DATATYPE:
2021 return ("datatype");
2022 case XML_RELAXNG_VALUE:
2023 return ("value");
2024 case XML_RELAXNG_LIST:
2025 return ("list");
2026 case XML_RELAXNG_ATTRIBUTE:
2027 return ("attribute");
2028 case XML_RELAXNG_DEF:
2029 return ("def");
2030 case XML_RELAXNG_REF:
2031 return ("ref");
2032 case XML_RELAXNG_EXTERNALREF:
2033 return ("externalRef");
2034 case XML_RELAXNG_PARENTREF:
2035 return ("parentRef");
2036 case XML_RELAXNG_OPTIONAL:
2037 return ("optional");
2038 case XML_RELAXNG_ZEROORMORE:
2039 return ("zeroOrMore");
2040 case XML_RELAXNG_ONEORMORE:
2041 return ("oneOrMore");
2042 case XML_RELAXNG_CHOICE:
2043 return ("choice");
2044 case XML_RELAXNG_GROUP:
2045 return ("group");
2046 case XML_RELAXNG_INTERLEAVE:
2047 return ("interleave");
2048 case XML_RELAXNG_START:
2049 return ("start");
2050 case XML_RELAXNG_NOOP:
2051 return ("noop");
2052 case XML_RELAXNG_PARAM:
2053 return ("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00002054 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002055 return ("unknown");
Daniel Veillard231d7912003-02-09 14:22:17 +00002056}
Daniel Veillardd2298792003-02-14 16:54:11 +00002057
Daniel Veillard6eadf632003-01-23 18:29:16 +00002058/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002059 * xmlRelaxNGGetErrorString:
2060 * @err: the error code
2061 * @arg1: the first string argument
2062 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00002063 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00002064 * computes a formatted error string for the given error code and args
2065 *
2066 * Returns the error string, it must be deallocated by the caller
2067 */
2068static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00002069xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
2070 const xmlChar * arg2)
2071{
Daniel Veillard42f12e92003-03-07 18:32:59 +00002072 char msg[1000];
2073
2074 if (arg1 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002075 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002076 if (arg2 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002077 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002078
2079 msg[0] = 0;
2080 switch (err) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002081 case XML_RELAXNG_OK:
2082 return (NULL);
2083 case XML_RELAXNG_ERR_MEMORY:
2084 return (xmlCharStrdup("out of memory\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002085 case XML_RELAXNG_ERR_TYPE:
Daniel Veillard4c004142003-10-07 11:33:24 +00002086 snprintf(msg, 1000, "failed to validate type %s\n", arg1);
2087 break;
2088 case XML_RELAXNG_ERR_TYPEVAL:
2089 snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
2090 arg2);
2091 break;
2092 case XML_RELAXNG_ERR_DUPID:
2093 snprintf(msg, 1000, "ID %s redefined\n", arg1);
2094 break;
2095 case XML_RELAXNG_ERR_TYPECMP:
2096 snprintf(msg, 1000, "failed to compare type %s\n", arg1);
2097 break;
2098 case XML_RELAXNG_ERR_NOSTATE:
2099 return (xmlCharStrdup("Internal error: no state\n"));
2100 case XML_RELAXNG_ERR_NODEFINE:
2101 return (xmlCharStrdup("Internal error: no define\n"));
2102 case XML_RELAXNG_ERR_INTERNAL:
2103 snprintf(msg, 1000, "Internal error: %s\n", arg1);
2104 break;
2105 case XML_RELAXNG_ERR_LISTEXTRA:
2106 snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
2107 break;
2108 case XML_RELAXNG_ERR_INTERNODATA:
2109 return (xmlCharStrdup
2110 ("Internal: interleave block has no data\n"));
2111 case XML_RELAXNG_ERR_INTERSEQ:
2112 return (xmlCharStrdup("Invalid sequence in interleave\n"));
2113 case XML_RELAXNG_ERR_INTEREXTRA:
2114 snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
2115 break;
2116 case XML_RELAXNG_ERR_ELEMNAME:
2117 snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
2118 arg2);
2119 break;
2120 case XML_RELAXNG_ERR_ELEMNONS:
2121 snprintf(msg, 1000, "Expecting a namespace for element %s\n",
2122 arg1);
2123 break;
2124 case XML_RELAXNG_ERR_ELEMWRONGNS:
2125 snprintf(msg, 1000,
2126 "Element %s has wrong namespace: expecting %s\n", arg1,
2127 arg2);
2128 break;
2129 case XML_RELAXNG_ERR_ELEMWRONG:
2130 snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
2131 break;
2132 case XML_RELAXNG_ERR_TEXTWRONG:
2133 snprintf(msg, 1000,
2134 "Did not expect text in element %s content\n", arg1);
2135 break;
2136 case XML_RELAXNG_ERR_ELEMEXTRANS:
2137 snprintf(msg, 1000, "Expecting no namespace for element %s\n",
2138 arg1);
2139 break;
2140 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
2141 snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
2142 break;
2143 case XML_RELAXNG_ERR_NOELEM:
2144 snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
2145 arg1);
2146 break;
2147 case XML_RELAXNG_ERR_NOTELEM:
2148 return (xmlCharStrdup("Expecting an element got text\n"));
2149 case XML_RELAXNG_ERR_ATTRVALID:
2150 snprintf(msg, 1000, "Element %s failed to validate attributes\n",
2151 arg1);
2152 break;
2153 case XML_RELAXNG_ERR_CONTENTVALID:
2154 snprintf(msg, 1000, "Element %s failed to validate content\n",
2155 arg1);
2156 break;
2157 case XML_RELAXNG_ERR_EXTRACONTENT:
2158 snprintf(msg, 1000, "Element %s has extra content: %s\n",
2159 arg1, arg2);
2160 break;
2161 case XML_RELAXNG_ERR_INVALIDATTR:
2162 snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
2163 arg1, arg2);
2164 break;
2165 case XML_RELAXNG_ERR_LACKDATA:
2166 snprintf(msg, 1000, "Datatype element %s contains no data\n",
2167 arg1);
2168 break;
2169 case XML_RELAXNG_ERR_DATAELEM:
2170 snprintf(msg, 1000, "Datatype element %s has child elements\n",
2171 arg1);
2172 break;
2173 case XML_RELAXNG_ERR_VALELEM:
2174 snprintf(msg, 1000, "Value element %s has child elements\n",
2175 arg1);
2176 break;
2177 case XML_RELAXNG_ERR_LISTELEM:
2178 snprintf(msg, 1000, "List element %s has child elements\n",
2179 arg1);
2180 break;
2181 case XML_RELAXNG_ERR_DATATYPE:
2182 snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
2183 break;
2184 case XML_RELAXNG_ERR_VALUE:
2185 snprintf(msg, 1000, "Error validating value %s\n", arg1);
2186 break;
2187 case XML_RELAXNG_ERR_LIST:
2188 return (xmlCharStrdup("Error validating list\n"));
2189 case XML_RELAXNG_ERR_NOGRAMMAR:
2190 return (xmlCharStrdup("No top grammar defined\n"));
2191 case XML_RELAXNG_ERR_EXTRADATA:
2192 return (xmlCharStrdup("Extra data in the document\n"));
2193 default:
2194 return (xmlCharStrdup("Unknown error !\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002195 }
2196 if (msg[0] == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002197 snprintf(msg, 1000, "Unknown error code %d\n", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002198 }
Daniel Veillardadbb0e62003-05-10 20:02:45 +00002199 msg[1000 - 1] = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00002200 return (xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002201}
2202
2203/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002204 * xmlRelaxNGShowValidError:
2205 * @ctxt: the validation context
2206 * @err: the error number
2207 * @node: the node
2208 * @child: the node child generating the problem.
2209 * @arg1: the first argument
2210 * @arg2: the second argument
2211 *
2212 * Show a validation error.
2213 */
2214static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002215xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
2216 xmlRelaxNGValidErr err, xmlNodePtr node,
2217 xmlNodePtr child, const xmlChar * arg1,
2218 const xmlChar * arg2)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002219{
2220 xmlChar *msg;
2221
2222 if (ctxt->error == NULL)
2223 return;
2224
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002225#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002226 xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002227#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002228 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2229 if (msg == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002230 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002231
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002232 if (ctxt->errNo == XML_RELAXNG_OK)
Daniel Veillard4c004142003-10-07 11:33:24 +00002233 ctxt->errNo = err;
2234 xmlRngVErr(ctxt, (child == NULL ? node : child), err,
2235 (const char *) msg, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002236 xmlFree(msg);
2237}
2238
2239/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002240 * xmlRelaxNGPopErrors:
2241 * @ctxt: the validation context
2242 * @level: the error level in the stack
2243 *
2244 * pop and discard all errors until the given level is reached
2245 */
2246static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002247xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
2248{
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002249 int i;
2250 xmlRelaxNGValidErrorPtr err;
2251
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002252#ifdef DEBUG_ERROR
2253 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002254 "Pop errors till level %d\n", level);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002255#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002256 for (i = level; i < ctxt->errNr; i++) {
2257 err = &ctxt->errTab[i];
2258 if (err->flags & ERROR_IS_DUP) {
2259 if (err->arg1 != NULL)
2260 xmlFree((xmlChar *) err->arg1);
2261 err->arg1 = NULL;
2262 if (err->arg2 != NULL)
2263 xmlFree((xmlChar *) err->arg2);
2264 err->arg2 = NULL;
2265 err->flags = 0;
2266 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002267 }
2268 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002269 if (ctxt->errNr <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002270 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002271}
Daniel Veillard4c004142003-10-07 11:33:24 +00002272
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002273/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002274 * xmlRelaxNGDumpValidError:
2275 * @ctxt: the validation context
2276 *
2277 * Show all validation error over a given index.
2278 */
2279static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002280xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
2281{
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002282 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002283 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002284
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002285#ifdef DEBUG_ERROR
2286 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002287 "Dumping error stack %d errors\n", ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002288#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002289 for (i = 0, k = 0; i < ctxt->errNr; i++) {
2290 err = &ctxt->errTab[i];
2291 if (k < MAX_ERROR) {
2292 for (j = 0; j < i; j++) {
2293 dup = &ctxt->errTab[j];
2294 if ((err->err == dup->err) && (err->node == dup->node) &&
2295 (xmlStrEqual(err->arg1, dup->arg1)) &&
2296 (xmlStrEqual(err->arg2, dup->arg2))) {
2297 goto skip;
2298 }
2299 }
2300 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2301 err->arg1, err->arg2);
2302 k++;
2303 }
2304 skip:
2305 if (err->flags & ERROR_IS_DUP) {
2306 if (err->arg1 != NULL)
2307 xmlFree((xmlChar *) err->arg1);
2308 err->arg1 = NULL;
2309 if (err->arg2 != NULL)
2310 xmlFree((xmlChar *) err->arg2);
2311 err->arg2 = NULL;
2312 err->flags = 0;
2313 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002314 }
2315 ctxt->errNr = 0;
2316}
Daniel Veillard4c004142003-10-07 11:33:24 +00002317
Daniel Veillard42f12e92003-03-07 18:32:59 +00002318/**
2319 * xmlRelaxNGAddValidError:
2320 * @ctxt: the validation context
2321 * @err: the error number
2322 * @arg1: the first argument
2323 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002324 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002325 *
2326 * Register a validation error, either generating it if it's sure
2327 * or stacking it for later handling if unsure.
2328 */
2329static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002330xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
2331 xmlRelaxNGValidErr err, const xmlChar * arg1,
2332 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002333{
2334 if ((ctxt == NULL) || (ctxt->error == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002335 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002336
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002337#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002338 xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002339#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002340 /*
2341 * generate the error directly
2342 */
2343 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002344 xmlNodePtr node, seq;
2345
2346 /*
2347 * Flush first any stacked error which might be the
2348 * real cause of the problem.
2349 */
2350 if (ctxt->errNr != 0)
2351 xmlRelaxNGDumpValidError(ctxt);
2352 if (ctxt->state != NULL) {
2353 node = ctxt->state->node;
2354 seq = ctxt->state->seq;
2355 } else {
2356 node = seq = NULL;
2357 }
2358 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002359 }
2360 /*
2361 * Stack the error for later processing if needed
2362 */
2363 else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002364 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002365 }
2366}
2367
Daniel Veillard6eadf632003-01-23 18:29:16 +00002368
2369/************************************************************************
2370 * *
2371 * Type library hooks *
2372 * *
2373 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002374static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00002375 const xmlChar * str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002376
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002377/**
2378 * xmlRelaxNGSchemaTypeHave:
2379 * @data: data needed for the library
2380 * @type: the type name
2381 *
2382 * Check if the given type is provided by
2383 * the W3C XMLSchema Datatype library.
2384 *
2385 * Returns 1 if yes, 0 if no and -1 in case of error.
2386 */
2387static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002388xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
2389{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002390 xmlSchemaTypePtr typ;
2391
2392 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002393 return (-1);
2394 typ = xmlSchemaGetPredefinedType(type,
2395 BAD_CAST
2396 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002397 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002398 return (0);
2399 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002400}
2401
2402/**
2403 * xmlRelaxNGSchemaTypeCheck:
2404 * @data: data needed for the library
2405 * @type: the type name
2406 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002407 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002408 *
2409 * Check if the given type and value are validated by
2410 * the W3C XMLSchema Datatype library.
2411 *
2412 * Returns 1 if yes, 0 if no and -1 in case of error.
2413 */
2414static int
2415xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002416 const xmlChar * type,
2417 const xmlChar * value,
2418 void **result, xmlNodePtr node)
2419{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002420 xmlSchemaTypePtr typ;
2421 int ret;
2422
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002423 if ((type == NULL) || (value == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002424 return (-1);
2425 typ = xmlSchemaGetPredefinedType(type,
2426 BAD_CAST
2427 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002428 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002429 return (-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002430 ret = xmlSchemaValPredefTypeNode(typ, value,
Daniel Veillard4c004142003-10-07 11:33:24 +00002431 (xmlSchemaValPtr *) result, node);
2432 if (ret == 2) /* special ID error code */
2433 return (2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002434 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002435 return (1);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002436 if (ret > 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002437 return (0);
2438 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002439}
2440
2441/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002442 * xmlRelaxNGSchemaFacetCheck:
2443 * @data: data needed for the library
2444 * @type: the type name
2445 * @facet: the facet name
2446 * @val: the facet value
2447 * @strval: the string value
2448 * @value: the value to check
2449 *
2450 * Function provided by a type library to check a value facet
2451 *
2452 * Returns 1 if yes, 0 if no and -1 in case of error.
2453 */
2454static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002455xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
2456 const xmlChar * type, const xmlChar * facetname,
2457 const xmlChar * val, const xmlChar * strval,
2458 void *value)
2459{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002460 xmlSchemaFacetPtr facet;
2461 xmlSchemaTypePtr typ;
2462 int ret;
2463
2464 if ((type == NULL) || (strval == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002465 return (-1);
2466 typ = xmlSchemaGetPredefinedType(type,
2467 BAD_CAST
2468 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002469 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002470 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002471
2472 facet = xmlSchemaNewFacet();
2473 if (facet == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002474 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002475
Daniel Veillard4c004142003-10-07 11:33:24 +00002476 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002477 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002478 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002479 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002480 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002481 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002482 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002483 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002484 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002485 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002486 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002487 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002488 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002489 facet->type = XML_SCHEMA_FACET_PATTERN;
Daniel Veillard4c004142003-10-07 11:33:24 +00002490 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002491 facet->type = XML_SCHEMA_FACET_ENUMERATION;
Daniel Veillard4c004142003-10-07 11:33:24 +00002492 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002493 facet->type = XML_SCHEMA_FACET_WHITESPACE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002494 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002495 facet->type = XML_SCHEMA_FACET_LENGTH;
Daniel Veillard4c004142003-10-07 11:33:24 +00002496 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002497 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2498 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2499 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2500 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002501 xmlSchemaFreeFacet(facet);
2502 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002503 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00002504 facet->value = val;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002505 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2506 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002507 xmlSchemaFreeFacet(facet);
2508 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002509 }
2510 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2511 xmlSchemaFreeFacet(facet);
2512 if (ret != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002513 return (-1);
2514 return (0);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002515}
2516
2517/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002518 * xmlRelaxNGSchemaFreeValue:
2519 * @data: data needed for the library
2520 * @value: the value to free
2521 *
2522 * Function provided by a type library to free a Schemas value
2523 *
2524 * Returns 1 if yes, 0 if no and -1 in case of error.
2525 */
2526static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002527xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
2528{
Daniel Veillard80b19092003-03-28 13:29:53 +00002529 xmlSchemaFreeValue(value);
2530}
2531
2532/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002533 * xmlRelaxNGSchemaTypeCompare:
2534 * @data: data needed for the library
2535 * @type: the type name
2536 * @value1: the first value
2537 * @value2: the second value
2538 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002539 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002540 * Datatype library.
2541 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002542 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002543 */
2544static int
2545xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002546 const xmlChar * type,
2547 const xmlChar * value1,
2548 xmlNodePtr ctxt1,
2549 void *comp1,
2550 const xmlChar * value2, xmlNodePtr ctxt2)
2551{
Daniel Veillard80b19092003-03-28 13:29:53 +00002552 int ret;
2553 xmlSchemaTypePtr typ;
2554 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2555
2556 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002557 return (-1);
2558 typ = xmlSchemaGetPredefinedType(type,
2559 BAD_CAST
2560 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard80b19092003-03-28 13:29:53 +00002561 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002562 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002563 if (comp1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002564 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2565 if (ret != 0)
2566 return (-1);
2567 if (res1 == NULL)
2568 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002569 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002570 res1 = (xmlSchemaValPtr) comp1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002571 }
2572 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002573 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002574 xmlSchemaFreeValue(res1);
2575 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002576 }
2577 if (res1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002578 xmlSchemaFreeValue(res1);
2579 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002580 }
2581 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002582 if (res1 != (xmlSchemaValPtr) comp1)
Daniel Veillard4c004142003-10-07 11:33:24 +00002583 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002584 xmlSchemaFreeValue(res2);
2585 if (ret == -2)
Daniel Veillard4c004142003-10-07 11:33:24 +00002586 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002587 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002588 return (1);
2589 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002590}
Daniel Veillard4c004142003-10-07 11:33:24 +00002591
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002592/**
2593 * xmlRelaxNGDefaultTypeHave:
2594 * @data: data needed for the library
2595 * @type: the type name
2596 *
2597 * Check if the given type is provided by
2598 * the default datatype library.
2599 *
2600 * Returns 1 if yes, 0 if no and -1 in case of error.
2601 */
2602static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002603xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
2604 const xmlChar * type)
2605{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002606 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002607 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002608 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002609 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002610 if (xmlStrEqual(type, BAD_CAST "token"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002611 return (1);
2612 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002613}
2614
2615/**
2616 * xmlRelaxNGDefaultTypeCheck:
2617 * @data: data needed for the library
2618 * @type: the type name
2619 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002620 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002621 *
2622 * Check if the given type and value are validated by
2623 * the default datatype library.
2624 *
2625 * Returns 1 if yes, 0 if no and -1 in case of error.
2626 */
2627static int
2628xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002629 const xmlChar * type ATTRIBUTE_UNUSED,
2630 const xmlChar * value ATTRIBUTE_UNUSED,
2631 void **result ATTRIBUTE_UNUSED,
2632 xmlNodePtr node ATTRIBUTE_UNUSED)
2633{
Daniel Veillardd4310742003-02-18 21:12:46 +00002634 if (value == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002635 return (-1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002636 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002637 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002638 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002639 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002640 }
2641
Daniel Veillard4c004142003-10-07 11:33:24 +00002642 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002643}
2644
2645/**
2646 * xmlRelaxNGDefaultTypeCompare:
2647 * @data: data needed for the library
2648 * @type: the type name
2649 * @value1: the first value
2650 * @value2: the second value
2651 *
2652 * Compare two values accordingly a type from the default
2653 * datatype library.
2654 *
2655 * Returns 1 if yes, 0 if no and -1 in case of error.
2656 */
2657static int
2658xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002659 const xmlChar * type,
2660 const xmlChar * value1,
2661 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2662 void *comp1 ATTRIBUTE_UNUSED,
2663 const xmlChar * value2,
2664 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
2665{
Daniel Veillardea3f3982003-01-26 19:45:18 +00002666 int ret = -1;
2667
2668 if (xmlStrEqual(type, BAD_CAST "string")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002669 ret = xmlStrEqual(value1, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002670 } else if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002671 if (!xmlStrEqual(value1, value2)) {
2672 xmlChar *nval, *nvalue;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002673
Daniel Veillard4c004142003-10-07 11:33:24 +00002674 /*
2675 * TODO: trivial optimizations are possible by
2676 * computing at compile-time
2677 */
2678 nval = xmlRelaxNGNormalize(NULL, value1);
2679 nvalue = xmlRelaxNGNormalize(NULL, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002680
Daniel Veillard4c004142003-10-07 11:33:24 +00002681 if ((nval == NULL) || (nvalue == NULL))
2682 ret = -1;
2683 else if (xmlStrEqual(nval, nvalue))
2684 ret = 1;
2685 else
2686 ret = 0;
2687 if (nval != NULL)
2688 xmlFree(nval);
2689 if (nvalue != NULL)
2690 xmlFree(nvalue);
2691 } else
2692 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002693 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002694 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002695}
Daniel Veillard4c004142003-10-07 11:33:24 +00002696
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002697static int xmlRelaxNGTypeInitialized = 0;
2698static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2699
2700/**
2701 * xmlRelaxNGFreeTypeLibrary:
2702 * @lib: the type library structure
2703 * @namespace: the URI bound to the library
2704 *
2705 * Free the structure associated to the type library
2706 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002707static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002708xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
Daniel Veillard4c004142003-10-07 11:33:24 +00002709 const xmlChar * namespace ATTRIBUTE_UNUSED)
2710{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002711 if (lib == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002712 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002713 if (lib->namespace != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002714 xmlFree((xmlChar *) lib->namespace);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002715 xmlFree(lib);
2716}
2717
2718/**
2719 * xmlRelaxNGRegisterTypeLibrary:
2720 * @namespace: the URI bound to the library
2721 * @data: data associated to the library
2722 * @have: the provide function
2723 * @check: the checking function
2724 * @comp: the comparison function
2725 *
2726 * Register a new type library
2727 *
2728 * Returns 0 in case of success and -1 in case of error.
2729 */
2730static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002731xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
2732 xmlRelaxNGTypeHave have,
2733 xmlRelaxNGTypeCheck check,
2734 xmlRelaxNGTypeCompare comp,
2735 xmlRelaxNGFacetCheck facet,
2736 xmlRelaxNGTypeFree freef)
2737{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002738 xmlRelaxNGTypeLibraryPtr lib;
2739 int ret;
2740
2741 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00002742 (check == NULL) || (comp == NULL))
2743 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002744 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002745 xmlGenericError(xmlGenericErrorContext,
2746 "Relax-NG types library '%s' already registered\n",
2747 namespace);
2748 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002749 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002750 lib =
2751 (xmlRelaxNGTypeLibraryPtr)
2752 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002753 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002754 xmlRngVErrMemory(NULL, "adding types library\n");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002755 return (-1);
2756 }
2757 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2758 lib->namespace = xmlStrdup(namespace);
2759 lib->data = data;
2760 lib->have = have;
2761 lib->comp = comp;
2762 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002763 lib->facet = facet;
2764 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002765 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2766 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002767 xmlGenericError(xmlGenericErrorContext,
2768 "Relax-NG types library failed to register '%s'\n",
2769 namespace);
2770 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2771 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002772 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002773 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002774}
2775
2776/**
2777 * xmlRelaxNGInitTypes:
2778 *
2779 * Initilize the default type libraries.
2780 *
2781 * Returns 0 in case of success and -1 in case of error.
2782 */
2783static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002784xmlRelaxNGInitTypes(void)
2785{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002786 if (xmlRelaxNGTypeInitialized != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002787 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002788 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2789 if (xmlRelaxNGRegisteredTypes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002790 xmlGenericError(xmlGenericErrorContext,
2791 "Failed to allocate sh table for Relax-NG types\n");
2792 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002793 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002794 xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2795 "http://www.w3.org/2001/XMLSchema-datatypes",
2796 NULL, xmlRelaxNGSchemaTypeHave,
2797 xmlRelaxNGSchemaTypeCheck,
2798 xmlRelaxNGSchemaTypeCompare,
2799 xmlRelaxNGSchemaFacetCheck,
2800 xmlRelaxNGSchemaFreeValue);
2801 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
2802 xmlRelaxNGDefaultTypeHave,
2803 xmlRelaxNGDefaultTypeCheck,
2804 xmlRelaxNGDefaultTypeCompare, NULL,
2805 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002806 xmlRelaxNGTypeInitialized = 1;
Daniel Veillard4c004142003-10-07 11:33:24 +00002807 return (0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002808}
2809
2810/**
2811 * xmlRelaxNGCleanupTypes:
2812 *
2813 * Cleanup the default Schemas type library associated to RelaxNG
2814 */
Daniel Veillard4c004142003-10-07 11:33:24 +00002815void
2816xmlRelaxNGCleanupTypes(void)
2817{
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002818 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002819 if (xmlRelaxNGTypeInitialized == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002820 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002821 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
Daniel Veillard4c004142003-10-07 11:33:24 +00002822 xmlRelaxNGFreeTypeLibrary);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002823 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002824}
2825
2826/************************************************************************
2827 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002828 * Compiling element content into regexp *
2829 * *
2830 * Sometime the element content can be compiled into a pure regexp, *
2831 * This allows a faster execution and streamability at that level *
2832 * *
2833 ************************************************************************/
2834
Daniel Veillard52b48c72003-04-13 19:53:42 +00002835static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2836 xmlRelaxNGDefinePtr def);
2837
Daniel Veillard952379b2003-03-17 15:37:12 +00002838/**
2839 * xmlRelaxNGIsCompileable:
2840 * @define: the definition to check
2841 *
2842 * Check if a definition is nullable.
2843 *
2844 * Returns 1 if yes, 0 if no and -1 in case of error
2845 */
2846static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002847xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def)
2848{
Daniel Veillard52b48c72003-04-13 19:53:42 +00002849 int ret = -1;
2850
Daniel Veillard952379b2003-03-17 15:37:12 +00002851 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002852 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00002853 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002854 if ((def->type != XML_RELAXNG_ELEMENT) &&
2855 (def->dflags & IS_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002856 return (1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002857 if ((def->type != XML_RELAXNG_ELEMENT) &&
2858 (def->dflags & IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002859 return (0);
2860 switch (def->type) {
Daniel Veillard952379b2003-03-17 15:37:12 +00002861 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002862 ret = xmlRelaxNGIsCompileable(def->content);
2863 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002864 case XML_RELAXNG_TEXT:
Daniel Veillard952379b2003-03-17 15:37:12 +00002865 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00002866 ret = 1;
2867 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002868 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00002869 /*
2870 * Check if the element content is compileable
2871 */
2872 if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2873 ((def->dflags & IS_COMPILABLE) == 0)) {
2874 xmlRelaxNGDefinePtr list;
2875
2876 list = def->content;
2877 while (list != NULL) {
2878 ret = xmlRelaxNGIsCompileable(list);
2879 if (ret != 1)
2880 break;
2881 list = list->next;
2882 }
2883 if (ret == 0)
2884 def->dflags |= IS_NOT_COMPILABLE;
2885 if (ret == 1)
2886 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002887#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00002888 if (ret == 1) {
2889 xmlGenericError(xmlGenericErrorContext,
2890 "element content for %s is compilable\n",
2891 def->name);
2892 } else if (ret == 0) {
2893 xmlGenericError(xmlGenericErrorContext,
2894 "element content for %s is not compilable\n",
2895 def->name);
2896 } else {
2897 xmlGenericError(xmlGenericErrorContext,
2898 "Problem in RelaxNGIsCompileable for element %s\n",
2899 def->name);
2900 }
Daniel Veillardd94849b2003-07-28 13:02:24 +00002901#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002902 }
2903 /*
2904 * All elements return a compileable status unless they
2905 * are generic like anyName
2906 */
2907 if ((def->nameClass != NULL) || (def->name == NULL))
2908 ret = 0;
2909 else
2910 ret = 1;
2911 return (ret);
Daniel Veillard2134ab12003-07-23 19:56:29 +00002912 case XML_RELAXNG_REF:
2913 case XML_RELAXNG_EXTERNALREF:
2914 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00002915 if (def->depth == -20) {
2916 return (1);
2917 } else {
2918 xmlRelaxNGDefinePtr list;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002919
Daniel Veillard4c004142003-10-07 11:33:24 +00002920 def->depth = -20;
2921 list = def->content;
2922 while (list != NULL) {
2923 ret = xmlRelaxNGIsCompileable(list);
2924 if (ret != 1)
2925 break;
2926 list = list->next;
2927 }
2928 }
2929 break;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002930 case XML_RELAXNG_START:
Daniel Veillard952379b2003-03-17 15:37:12 +00002931 case XML_RELAXNG_OPTIONAL:
2932 case XML_RELAXNG_ZEROORMORE:
2933 case XML_RELAXNG_ONEORMORE:
2934 case XML_RELAXNG_CHOICE:
2935 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002936 case XML_RELAXNG_DEF:{
2937 xmlRelaxNGDefinePtr list;
Daniel Veillard952379b2003-03-17 15:37:12 +00002938
Daniel Veillard4c004142003-10-07 11:33:24 +00002939 list = def->content;
2940 while (list != NULL) {
2941 ret = xmlRelaxNGIsCompileable(list);
2942 if (ret != 1)
2943 break;
2944 list = list->next;
2945 }
2946 break;
2947 }
Daniel Veillard952379b2003-03-17 15:37:12 +00002948 case XML_RELAXNG_EXCEPT:
2949 case XML_RELAXNG_ATTRIBUTE:
2950 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002951 case XML_RELAXNG_DATATYPE:
2952 case XML_RELAXNG_LIST:
2953 case XML_RELAXNG_PARAM:
2954 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00002955 ret = 0;
2956 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002957 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00002958 ret = -1;
2959 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002960 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002961 if (ret == 0)
2962 def->dflags |= IS_NOT_COMPILABLE;
2963 if (ret == 1)
2964 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002965#ifdef DEBUG_COMPILE
2966 if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002967 xmlGenericError(xmlGenericErrorContext,
2968 "RelaxNGIsCompileable %s : true\n",
2969 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002970 } else if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002971 xmlGenericError(xmlGenericErrorContext,
2972 "RelaxNGIsCompileable %s : false\n",
2973 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002974 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002975 xmlGenericError(xmlGenericErrorContext,
2976 "Problem in RelaxNGIsCompileable %s\n",
2977 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002978 }
2979#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002980 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002981}
2982
2983/**
2984 * xmlRelaxNGCompile:
2985 * ctxt: the RelaxNG parser context
2986 * @define: the definition tree to compile
2987 *
2988 * Compile the set of definitions, it works recursively, till the
2989 * element boundaries, where it tries to compile the content if possible
2990 *
2991 * Returns 0 if success and -1 in case of error
2992 */
2993static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002994xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
2995{
Daniel Veillard52b48c72003-04-13 19:53:42 +00002996 int ret = 0;
2997 xmlRelaxNGDefinePtr list;
2998
Daniel Veillard4c004142003-10-07 11:33:24 +00002999 if ((ctxt == NULL) || (def == NULL))
3000 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003001
Daniel Veillard4c004142003-10-07 11:33:24 +00003002 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003003 case XML_RELAXNG_START:
3004 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003005 xmlAutomataPtr oldam = ctxt->am;
3006 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003007
3008 def->depth = -25;
3009
Daniel Veillard4c004142003-10-07 11:33:24 +00003010 list = def->content;
3011 ctxt->am = xmlNewAutomata();
3012 if (ctxt->am == NULL)
3013 return (-1);
3014 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3015 while (list != NULL) {
3016 xmlRelaxNGCompile(ctxt, list);
3017 list = list->next;
3018 }
3019 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3020 def->contModel = xmlAutomataCompile(ctxt->am);
3021 xmlRegexpIsDeterminist(def->contModel);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003022
Daniel Veillard4c004142003-10-07 11:33:24 +00003023 xmlFreeAutomata(ctxt->am);
3024 ctxt->state = oldstate;
3025 ctxt->am = oldam;
3026 }
3027 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003028 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003029 if ((ctxt->am != NULL) && (def->name != NULL)) {
3030 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
3031 ctxt->state, NULL,
3032 def->name, def->ns,
3033 def);
3034 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003035 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003036 xmlAutomataPtr oldam = ctxt->am;
3037 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003038
3039 def->depth = -25;
3040
Daniel Veillard4c004142003-10-07 11:33:24 +00003041 list = def->content;
3042 ctxt->am = xmlNewAutomata();
3043 if (ctxt->am == NULL)
3044 return (-1);
3045 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3046 while (list != NULL) {
3047 xmlRelaxNGCompile(ctxt, list);
3048 list = list->next;
3049 }
3050 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3051 def->contModel = xmlAutomataCompile(ctxt->am);
3052 if (!xmlRegexpIsDeterminist(def->contModel)) {
3053 /*
3054 * we can only use the automata if it is determinist
3055 */
3056 xmlRegFreeRegexp(def->contModel);
3057 def->contModel = NULL;
3058 }
3059 xmlFreeAutomata(ctxt->am);
3060 ctxt->state = oldstate;
3061 ctxt->am = oldam;
3062 } else {
3063 xmlAutomataPtr oldam = ctxt->am;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003064
Daniel Veillard4c004142003-10-07 11:33:24 +00003065 /*
3066 * we can't build the content model for this element content
3067 * but it still might be possible to build it for some of its
3068 * children, recurse.
3069 */
3070 ret = xmlRelaxNGTryCompile(ctxt, def);
3071 ctxt->am = oldam;
3072 }
3073 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003074 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003075 ret = xmlRelaxNGCompile(ctxt, def->content);
3076 break;
3077 case XML_RELAXNG_OPTIONAL:{
3078 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003079
Daniel Veillard4c004142003-10-07 11:33:24 +00003080 xmlRelaxNGCompile(ctxt, def->content);
3081 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3082 break;
3083 }
3084 case XML_RELAXNG_ZEROORMORE:{
3085 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003086
Daniel Veillard4c004142003-10-07 11:33:24 +00003087 ctxt->state =
3088 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3089 oldstate = ctxt->state;
3090 list = def->content;
3091 while (list != NULL) {
3092 xmlRelaxNGCompile(ctxt, list);
3093 list = list->next;
3094 }
3095 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3096 ctxt->state =
3097 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3098 break;
3099 }
3100 case XML_RELAXNG_ONEORMORE:{
3101 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003102
Daniel Veillard4c004142003-10-07 11:33:24 +00003103 list = def->content;
3104 while (list != NULL) {
3105 xmlRelaxNGCompile(ctxt, list);
3106 list = list->next;
3107 }
3108 oldstate = ctxt->state;
3109 list = def->content;
3110 while (list != NULL) {
3111 xmlRelaxNGCompile(ctxt, list);
3112 list = list->next;
3113 }
3114 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3115 ctxt->state =
3116 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3117 break;
3118 }
3119 case XML_RELAXNG_CHOICE:{
3120 xmlAutomataStatePtr target = NULL;
3121 xmlAutomataStatePtr oldstate = ctxt->state;
3122
3123 list = def->content;
3124 while (list != NULL) {
3125 ctxt->state = oldstate;
3126 ret = xmlRelaxNGCompile(ctxt, list);
3127 if (ret != 0)
3128 break;
3129 if (target == NULL)
3130 target = ctxt->state;
3131 else {
3132 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3133 target);
3134 }
3135 list = list->next;
3136 }
3137 ctxt->state = target;
3138
3139 break;
3140 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003141 case XML_RELAXNG_REF:
3142 case XML_RELAXNG_EXTERNALREF:
3143 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00003144 case XML_RELAXNG_GROUP:
3145 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003146 list = def->content;
3147 while (list != NULL) {
3148 ret = xmlRelaxNGCompile(ctxt, list);
3149 if (ret != 0)
3150 break;
3151 list = list->next;
3152 }
3153 break;
3154 case XML_RELAXNG_TEXT:{
3155 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003156
Daniel Veillard4c004142003-10-07 11:33:24 +00003157 ctxt->state =
3158 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3159 oldstate = ctxt->state;
3160 xmlRelaxNGCompile(ctxt, def->content);
3161 xmlAutomataNewTransition(ctxt->am, ctxt->state,
3162 ctxt->state, BAD_CAST "#text",
3163 NULL);
3164 ctxt->state =
3165 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3166 break;
3167 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003168 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00003169 ctxt->state =
3170 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3171 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003172 case XML_RELAXNG_EXCEPT:
3173 case XML_RELAXNG_ATTRIBUTE:
3174 case XML_RELAXNG_INTERLEAVE:
3175 case XML_RELAXNG_NOT_ALLOWED:
3176 case XML_RELAXNG_DATATYPE:
3177 case XML_RELAXNG_LIST:
3178 case XML_RELAXNG_PARAM:
3179 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003180 /* This should not happen and generate an internal error */
3181 fprintf(stderr, "RNG internal error trying to compile %s\n",
3182 xmlRelaxNGDefName(def));
3183 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003184 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003185 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003186}
3187
3188/**
3189 * xmlRelaxNGTryCompile:
3190 * ctxt: the RelaxNG parser context
3191 * @define: the definition tree to compile
3192 *
3193 * Try to compile the set of definitions, it works recursively,
3194 * possibly ignoring parts which cannot be compiled.
3195 *
3196 * Returns 0 if success and -1 in case of error
3197 */
3198static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003199xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3200{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003201 int ret = 0;
3202 xmlRelaxNGDefinePtr list;
3203
Daniel Veillard4c004142003-10-07 11:33:24 +00003204 if ((ctxt == NULL) || (def == NULL))
3205 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003206
3207 if ((def->type == XML_RELAXNG_START) ||
3208 (def->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003209 ret = xmlRelaxNGIsCompileable(def);
3210 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3211 ctxt->am = NULL;
3212 ret = xmlRelaxNGCompile(ctxt, def);
Daniel Veillard2134ab12003-07-23 19:56:29 +00003213#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00003214 if (ret == 0) {
3215 if (def->type == XML_RELAXNG_START)
3216 xmlGenericError(xmlGenericErrorContext,
3217 "compiled the start\n");
3218 else
3219 xmlGenericError(xmlGenericErrorContext,
3220 "compiled element %s\n", def->name);
3221 } else {
3222 if (def->type == XML_RELAXNG_START)
3223 xmlGenericError(xmlGenericErrorContext,
3224 "failed to compile the start\n");
3225 else
3226 xmlGenericError(xmlGenericErrorContext,
3227 "failed to compile element %s\n",
3228 def->name);
3229 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003230#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00003231 return (ret);
3232 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003233 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003234 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003235 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003236 ret = xmlRelaxNGTryCompile(ctxt, def->content);
3237 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003238 case XML_RELAXNG_TEXT:
3239 case XML_RELAXNG_DATATYPE:
3240 case XML_RELAXNG_LIST:
3241 case XML_RELAXNG_PARAM:
3242 case XML_RELAXNG_VALUE:
3243 case XML_RELAXNG_EMPTY:
3244 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003245 ret = 0;
3246 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003247 case XML_RELAXNG_OPTIONAL:
3248 case XML_RELAXNG_ZEROORMORE:
3249 case XML_RELAXNG_ONEORMORE:
3250 case XML_RELAXNG_CHOICE:
3251 case XML_RELAXNG_GROUP:
3252 case XML_RELAXNG_DEF:
Daniel Veillard2134ab12003-07-23 19:56:29 +00003253 case XML_RELAXNG_START:
3254 case XML_RELAXNG_REF:
3255 case XML_RELAXNG_EXTERNALREF:
3256 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003257 list = def->content;
3258 while (list != NULL) {
3259 ret = xmlRelaxNGTryCompile(ctxt, list);
3260 if (ret != 0)
3261 break;
3262 list = list->next;
3263 }
3264 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003265 case XML_RELAXNG_EXCEPT:
3266 case XML_RELAXNG_ATTRIBUTE:
3267 case XML_RELAXNG_INTERLEAVE:
3268 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00003269 ret = 0;
3270 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003271 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003272 return (ret);
Daniel Veillard952379b2003-03-17 15:37:12 +00003273}
3274
3275/************************************************************************
3276 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00003277 * Parsing functions *
3278 * *
3279 ************************************************************************/
3280
Daniel Veillard4c004142003-10-07 11:33:24 +00003281static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3282 ctxt, xmlNodePtr node);
3283static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3284 ctxt, xmlNodePtr node);
3285static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3286 ctxt, xmlNodePtr nodes,
3287 int group);
3288static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3289 ctxt, xmlNodePtr node);
3290static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3291 xmlNodePtr node);
3292static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3293 xmlNodePtr nodes);
3294static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3295 ctxt, xmlNodePtr node,
3296 xmlRelaxNGDefinePtr
3297 def);
3298static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3299 ctxt, xmlNodePtr nodes);
3300static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3301 xmlRelaxNGDefinePtr define,
3302 xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003303
3304
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003305#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00003306
3307/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003308 * xmlRelaxNGIsNullable:
3309 * @define: the definition to verify
3310 *
3311 * Check if a definition is nullable.
3312 *
3313 * Returns 1 if yes, 0 if no and -1 in case of error
3314 */
3315static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003316xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3317{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003318 int ret;
Daniel Veillard4c004142003-10-07 11:33:24 +00003319
Daniel Veillardfd573f12003-03-16 17:52:32 +00003320 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003321 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003322
Daniel Veillarde063f482003-03-21 16:53:17 +00003323 if (define->dflags & IS_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003324 return (1);
Daniel Veillarde063f482003-03-21 16:53:17 +00003325 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003326 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003327 switch (define->type) {
3328 case XML_RELAXNG_EMPTY:
3329 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003330 ret = 1;
3331 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003332 case XML_RELAXNG_NOOP:
3333 case XML_RELAXNG_DEF:
3334 case XML_RELAXNG_REF:
3335 case XML_RELAXNG_EXTERNALREF:
3336 case XML_RELAXNG_PARENTREF:
3337 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003338 ret = xmlRelaxNGIsNullable(define->content);
3339 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003340 case XML_RELAXNG_EXCEPT:
3341 case XML_RELAXNG_NOT_ALLOWED:
3342 case XML_RELAXNG_ELEMENT:
3343 case XML_RELAXNG_DATATYPE:
3344 case XML_RELAXNG_PARAM:
3345 case XML_RELAXNG_VALUE:
3346 case XML_RELAXNG_LIST:
3347 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003348 ret = 0;
3349 break;
3350 case XML_RELAXNG_CHOICE:{
3351 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003352
Daniel Veillard4c004142003-10-07 11:33:24 +00003353 while (list != NULL) {
3354 ret = xmlRelaxNGIsNullable(list);
3355 if (ret != 0)
3356 goto done;
3357 list = list->next;
3358 }
3359 ret = 0;
3360 break;
3361 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003362 case XML_RELAXNG_START:
3363 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003364 case XML_RELAXNG_GROUP:{
3365 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003366
Daniel Veillard4c004142003-10-07 11:33:24 +00003367 while (list != NULL) {
3368 ret = xmlRelaxNGIsNullable(list);
3369 if (ret != 1)
3370 goto done;
3371 list = list->next;
3372 }
3373 return (1);
3374 }
3375 default:
3376 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003377 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003378 done:
Daniel Veillardfd573f12003-03-16 17:52:32 +00003379 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003380 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003381 if (ret == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00003382 define->dflags |= IS_NULLABLE;
3383 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003384}
3385
3386/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003387 * xmlRelaxNGIsBlank:
3388 * @str: a string
3389 *
3390 * Check if a string is ignorable c.f. 4.2. Whitespace
3391 *
3392 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3393 */
3394static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003395xmlRelaxNGIsBlank(xmlChar * str)
3396{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003397 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003398 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003399 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003400 if (!(IS_BLANK_CH(*str)))
Daniel Veillard4c004142003-10-07 11:33:24 +00003401 return (0);
3402 str++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003403 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003404 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003405}
3406
Daniel Veillard6eadf632003-01-23 18:29:16 +00003407/**
3408 * xmlRelaxNGGetDataTypeLibrary:
3409 * @ctxt: a Relax-NG parser context
3410 * @node: the current data or value element
3411 *
3412 * Applies algorithm from 4.3. datatypeLibrary attribute
3413 *
3414 * Returns the datatypeLibary value or NULL if not found
3415 */
3416static xmlChar *
3417xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00003418 xmlNodePtr node)
3419{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003420 xmlChar *ret, *escape;
3421
Daniel Veillard6eadf632003-01-23 18:29:16 +00003422 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003423 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3424 if (ret != NULL) {
3425 if (ret[0] == 0) {
3426 xmlFree(ret);
3427 return (NULL);
3428 }
3429 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3430 if (escape == NULL) {
3431 return (ret);
3432 }
3433 xmlFree(ret);
3434 return (escape);
3435 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003436 }
3437 node = node->parent;
3438 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003439 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3440 if (ret != NULL) {
3441 if (ret[0] == 0) {
3442 xmlFree(ret);
3443 return (NULL);
3444 }
3445 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3446 if (escape == NULL) {
3447 return (ret);
3448 }
3449 xmlFree(ret);
3450 return (escape);
3451 }
3452 node = node->parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003453 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003454 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003455}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003456
3457/**
Daniel Veillardedc91922003-01-26 00:52:04 +00003458 * xmlRelaxNGParseValue:
3459 * @ctxt: a Relax-NG parser context
3460 * @node: the data node.
3461 *
3462 * parse the content of a RelaxNG value node.
3463 *
3464 * Returns the definition pointer or NULL in case of error
3465 */
3466static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003467xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3468{
Daniel Veillardedc91922003-01-26 00:52:04 +00003469 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00003470 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00003471 xmlChar *type;
3472 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003473 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00003474
Daniel Veillardfd573f12003-03-16 17:52:32 +00003475 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003476 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003477 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003478 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00003479
3480 type = xmlGetProp(node, BAD_CAST "type");
3481 if (type != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003482 xmlRelaxNGNormExtSpace(type);
3483 if (xmlValidateNCName(type, 0)) {
3484 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3485 "value type '%s' is not an NCName\n", type, NULL);
3486 }
3487 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3488 if (library == NULL)
3489 library =
3490 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillardedc91922003-01-26 00:52:04 +00003491
Daniel Veillard4c004142003-10-07 11:33:24 +00003492 def->name = type;
3493 def->ns = library;
Daniel Veillardedc91922003-01-26 00:52:04 +00003494
Daniel Veillard4c004142003-10-07 11:33:24 +00003495 lib = (xmlRelaxNGTypeLibraryPtr)
3496 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3497 if (lib == NULL) {
3498 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3499 "Use of unregistered type library '%s'\n", library,
3500 NULL);
3501 def->data = NULL;
3502 } else {
3503 def->data = lib;
3504 if (lib->have == NULL) {
3505 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3506 "Internal error with type library '%s': no 'have'\n",
3507 library, NULL);
3508 } else {
3509 success = lib->have(lib->data, def->name);
3510 if (success != 1) {
3511 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3512 "Error type '%s' is not exported by type library '%s'\n",
3513 def->name, library);
3514 }
3515 }
3516 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003517 }
3518 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003519 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00003520 } else if (((node->children->type != XML_TEXT_NODE) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00003521 (node->children->type != XML_CDATA_SECTION_NODE)) ||
3522 (node->children->next != NULL)) {
3523 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3524 "Expecting a single text value for <value>content\n",
3525 NULL, NULL);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003526 } else if (def != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003527 def->value = xmlNodeGetContent(node);
3528 if (def->value == NULL) {
3529 xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3530 "Element <value> has no content\n", NULL, NULL);
3531 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3532 void *val = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003533
Daniel Veillard4c004142003-10-07 11:33:24 +00003534 success =
3535 lib->check(lib->data, def->name, def->value, &val, node);
3536 if (success != 1) {
3537 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3538 "Value '%s' is not acceptable for type '%s'\n",
3539 def->value, def->name);
3540 } else {
3541 if (val != NULL)
3542 def->attrs = val;
3543 }
3544 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003545 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003546 return (def);
Daniel Veillardedc91922003-01-26 00:52:04 +00003547}
3548
3549/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003550 * xmlRelaxNGParseData:
3551 * @ctxt: a Relax-NG parser context
3552 * @node: the data node.
3553 *
3554 * parse the content of a RelaxNG data node.
3555 *
3556 * Returns the definition pointer or NULL in case of error
3557 */
3558static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003559xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3560{
Daniel Veillard416589a2003-02-17 17:25:42 +00003561 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003562 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003563 xmlRelaxNGTypeLibraryPtr lib;
3564 xmlChar *type;
3565 xmlChar *library;
3566 xmlNodePtr content;
3567 int tmp;
3568
3569 type = xmlGetProp(node, BAD_CAST "type");
3570 if (type == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003571 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3572 NULL);
3573 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003574 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003575 xmlRelaxNGNormExtSpace(type);
3576 if (xmlValidateNCName(type, 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003577 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3578 "data type '%s' is not an NCName\n", type, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003579 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003580 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3581 if (library == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003582 library =
3583 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003584
Daniel Veillardfd573f12003-03-16 17:52:32 +00003585 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003586 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003587 xmlFree(type);
3588 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003589 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003590 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003591 def->name = type;
3592 def->ns = library;
3593
3594 lib = (xmlRelaxNGTypeLibraryPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00003595 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003596 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003597 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3598 "Use of unregistered type library '%s'\n", library,
3599 NULL);
3600 def->data = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003601 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003602 def->data = lib;
3603 if (lib->have == NULL) {
3604 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3605 "Internal error with type library '%s': no 'have'\n",
3606 library, NULL);
3607 } else {
3608 tmp = lib->have(lib->data, def->name);
3609 if (tmp != 1) {
3610 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3611 "Error type '%s' is not exported by type library '%s'\n",
3612 def->name, library);
3613 } else
3614 if ((xmlStrEqual
3615 (library,
3616 BAD_CAST
3617 "http://www.w3.org/2001/XMLSchema-datatypes"))
3618 && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3619 || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3620 ctxt->idref = 1;
3621 }
3622 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003623 }
3624 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003625
3626 /*
3627 * Handle optional params
3628 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003629 while (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003630 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3631 break;
3632 if (xmlStrEqual(library,
3633 BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3634 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3635 "Type library '%s' does not allow type parameters\n",
3636 library, NULL);
3637 content = content->next;
3638 while ((content != NULL) &&
3639 (xmlStrEqual(content->name, BAD_CAST "param")))
3640 content = content->next;
3641 } else {
3642 param = xmlRelaxNGNewDefine(ctxt, node);
3643 if (param != NULL) {
3644 param->type = XML_RELAXNG_PARAM;
3645 param->name = xmlGetProp(content, BAD_CAST "name");
3646 if (param->name == NULL) {
3647 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3648 "param has no name\n", NULL, NULL);
3649 }
3650 param->value = xmlNodeGetContent(content);
3651 if (lastparam == NULL) {
3652 def->attrs = lastparam = param;
3653 } else {
3654 lastparam->next = param;
3655 lastparam = param;
3656 }
3657 if (lib != NULL) {
3658 }
3659 }
3660 content = content->next;
3661 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003662 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003663 /*
3664 * Handle optional except
3665 */
Daniel Veillard4c004142003-10-07 11:33:24 +00003666 if ((content != NULL)
3667 && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3668 xmlNodePtr child;
3669 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
Daniel Veillard416589a2003-02-17 17:25:42 +00003670
Daniel Veillard4c004142003-10-07 11:33:24 +00003671 except = xmlRelaxNGNewDefine(ctxt, node);
3672 if (except == NULL) {
3673 return (def);
3674 }
3675 except->type = XML_RELAXNG_EXCEPT;
3676 child = content->children;
3677 if (last == NULL) {
3678 def->content = except;
3679 } else {
3680 last->next = except;
3681 }
3682 if (child == NULL) {
3683 xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3684 "except has no content\n", NULL, NULL);
3685 }
3686 while (child != NULL) {
3687 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3688 if (tmp2 != NULL) {
3689 if (last2 == NULL) {
3690 except->content = last2 = tmp2;
3691 } else {
3692 last2->next = tmp2;
3693 last2 = tmp2;
3694 }
3695 }
3696 child = child->next;
3697 }
3698 content = content->next;
Daniel Veillard416589a2003-02-17 17:25:42 +00003699 }
3700 /*
3701 * Check there is no unhandled data
3702 */
3703 if (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003704 xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3705 "Element data has unexpected content %s\n",
3706 content->name, NULL);
Daniel Veillard416589a2003-02-17 17:25:42 +00003707 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003708
Daniel Veillard4c004142003-10-07 11:33:24 +00003709 return (def);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003710}
3711
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003712static const xmlChar *invalidName = BAD_CAST "\1";
3713
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003714/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003715 * xmlRelaxNGCompareNameClasses:
3716 * @defs1: the first element/attribute defs
3717 * @defs2: the second element/attribute defs
3718 * @name: the restriction on the name
3719 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003720 *
3721 * Compare the 2 lists of element definitions. The comparison is
3722 * that if both lists do not accept the same QNames, it returns 1
3723 * If the 2 lists can accept the same QName the comparison returns 0
3724 *
3725 * Returns 1 disttinct, 0 if equal
3726 */
3727static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003728xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
Daniel Veillard4c004142003-10-07 11:33:24 +00003729 xmlRelaxNGDefinePtr def2)
3730{
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003731 int ret = 1;
3732 xmlNode node;
3733 xmlNs ns;
3734 xmlRelaxNGValidCtxt ctxt;
Daniel Veillard4c004142003-10-07 11:33:24 +00003735
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003736 ctxt.flags = FLAGS_IGNORABLE;
3737
Daniel Veillard42f12e92003-03-07 18:32:59 +00003738 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3739
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003740 if ((def1->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003741 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3742 if (def2->type == XML_RELAXNG_TEXT)
3743 return (1);
3744 if (def1->name != NULL) {
3745 node.name = def1->name;
3746 } else {
3747 node.name = invalidName;
3748 }
3749 node.ns = &ns;
3750 if (def1->ns != NULL) {
3751 if (def1->ns[0] == 0) {
3752 node.ns = NULL;
3753 } else {
3754 ns.href = def1->ns;
3755 }
3756 } else {
3757 ns.href = invalidName;
3758 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003759 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003760 if (def1->nameClass != NULL) {
3761 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3762 } else {
3763 ret = 0;
3764 }
3765 } else {
3766 ret = 1;
3767 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003768 } else if (def1->type == XML_RELAXNG_TEXT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003769 if (def2->type == XML_RELAXNG_TEXT)
3770 return (0);
3771 return (1);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003772 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003773 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003774 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003775 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003776 }
3777 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003778 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003779 if ((def2->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003780 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3781 if (def2->name != NULL) {
3782 node.name = def2->name;
3783 } else {
3784 node.name = invalidName;
3785 }
3786 node.ns = &ns;
3787 if (def2->ns != NULL) {
3788 if (def2->ns[0] == 0) {
3789 node.ns = NULL;
3790 } else {
3791 ns.href = def2->ns;
3792 }
3793 } else {
3794 ns.href = invalidName;
3795 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003796 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003797 if (def2->nameClass != NULL) {
3798 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3799 } else {
3800 ret = 0;
3801 }
3802 } else {
3803 ret = 1;
3804 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003805 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003806 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003807 }
3808
Daniel Veillard4c004142003-10-07 11:33:24 +00003809 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003810}
3811
3812/**
3813 * xmlRelaxNGCompareElemDefLists:
3814 * @ctxt: a Relax-NG parser context
3815 * @defs1: the first list of element/attribute defs
3816 * @defs2: the second list of element/attribute defs
3817 *
3818 * Compare the 2 lists of element or attribute definitions. The comparison
3819 * is that if both lists do not accept the same QNames, it returns 1
3820 * If the 2 lists can accept the same QName the comparison returns 0
3821 *
3822 * Returns 1 disttinct, 0 if equal
3823 */
3824static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003825xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3826 ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3827 xmlRelaxNGDefinePtr * def2)
3828{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003829 xmlRelaxNGDefinePtr *basedef2 = def2;
Daniel Veillard4c004142003-10-07 11:33:24 +00003830
Daniel Veillard154877e2003-01-30 12:17:05 +00003831 if ((def1 == NULL) || (def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003832 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003833 if ((*def1 == NULL) || (*def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003834 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003835 while (*def1 != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003836 while ((*def2) != NULL) {
3837 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3838 return (0);
3839 def2++;
3840 }
3841 def2 = basedef2;
3842 def1++;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003843 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003844 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003845}
3846
3847/**
Daniel Veillardce192eb2003-04-16 15:58:05 +00003848 * xmlRelaxNGGenerateAttributes:
3849 * @ctxt: a Relax-NG parser context
3850 * @def: the definition definition
3851 *
3852 * Check if the definition can only generate attributes
3853 *
3854 * Returns 1 if yes, 0 if no and -1 in case of error.
3855 */
3856static int
3857xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003858 xmlRelaxNGDefinePtr def)
3859{
Daniel Veillardce192eb2003-04-16 15:58:05 +00003860 xmlRelaxNGDefinePtr parent, cur, tmp;
3861
3862 /*
3863 * Don't run that check in case of error. Infinite recursion
3864 * becomes possible.
3865 */
3866 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003867 return (-1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003868
3869 parent = NULL;
3870 cur = def;
3871 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003872 if ((cur->type == XML_RELAXNG_ELEMENT) ||
3873 (cur->type == XML_RELAXNG_TEXT) ||
3874 (cur->type == XML_RELAXNG_DATATYPE) ||
3875 (cur->type == XML_RELAXNG_PARAM) ||
3876 (cur->type == XML_RELAXNG_LIST) ||
3877 (cur->type == XML_RELAXNG_VALUE) ||
3878 (cur->type == XML_RELAXNG_EMPTY))
3879 return (0);
3880 if ((cur->type == XML_RELAXNG_CHOICE) ||
3881 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3882 (cur->type == XML_RELAXNG_GROUP) ||
3883 (cur->type == XML_RELAXNG_ONEORMORE) ||
3884 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3885 (cur->type == XML_RELAXNG_OPTIONAL) ||
3886 (cur->type == XML_RELAXNG_PARENTREF) ||
3887 (cur->type == XML_RELAXNG_EXTERNALREF) ||
3888 (cur->type == XML_RELAXNG_REF) ||
3889 (cur->type == XML_RELAXNG_DEF)) {
3890 if (cur->content != NULL) {
3891 parent = cur;
3892 cur = cur->content;
3893 tmp = cur;
3894 while (tmp != NULL) {
3895 tmp->parent = parent;
3896 tmp = tmp->next;
3897 }
3898 continue;
3899 }
3900 }
3901 if (cur == def)
3902 break;
3903 if (cur->next != NULL) {
3904 cur = cur->next;
3905 continue;
3906 }
3907 do {
3908 cur = cur->parent;
3909 if (cur == NULL)
3910 break;
3911 if (cur == def)
3912 return (1);
3913 if (cur->next != NULL) {
3914 cur = cur->next;
3915 break;
3916 }
3917 } while (cur != NULL);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003918 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003919 return (1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003920}
Daniel Veillard4c004142003-10-07 11:33:24 +00003921
Daniel Veillardce192eb2003-04-16 15:58:05 +00003922/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003923 * xmlRelaxNGGetElements:
3924 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003925 * @def: the definition definition
3926 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003927 *
3928 * Compute the list of top elements a definition can generate
3929 *
3930 * Returns a list of elements or NULL if none was found.
3931 */
3932static xmlRelaxNGDefinePtr *
3933xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003934 xmlRelaxNGDefinePtr def, int eora)
3935{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003936 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003937 int len = 0;
3938 int max = 0;
3939
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003940 /*
3941 * Don't run that check in case of error. Infinite recursion
3942 * becomes possible.
3943 */
3944 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003945 return (NULL);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003946
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003947 parent = NULL;
3948 cur = def;
3949 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003950 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3951 (cur->type == XML_RELAXNG_TEXT))) ||
3952 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
3953 if (ret == NULL) {
3954 max = 10;
3955 ret = (xmlRelaxNGDefinePtr *)
3956 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3957 if (ret == NULL) {
3958 xmlRngPErrMemory(ctxt, "getting element list\n");
3959 return (NULL);
3960 }
3961 } else if (max <= len) {
3962 max *= 2;
3963 ret =
3964 xmlRealloc(ret,
3965 (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3966 if (ret == NULL) {
3967 xmlRngPErrMemory(ctxt, "getting element list\n");
3968 return (NULL);
3969 }
3970 }
3971 ret[len++] = cur;
3972 ret[len] = NULL;
3973 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3974 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3975 (cur->type == XML_RELAXNG_GROUP) ||
3976 (cur->type == XML_RELAXNG_ONEORMORE) ||
3977 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3978 (cur->type == XML_RELAXNG_OPTIONAL) ||
3979 (cur->type == XML_RELAXNG_PARENTREF) ||
3980 (cur->type == XML_RELAXNG_REF) ||
William M. Brack236c8c02004-03-20 11:32:36 +00003981 (cur->type == XML_RELAXNG_DEF) ||
3982 (cur->type == XML_RELAXNG_EXTERNALREF)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003983 /*
3984 * Don't go within elements or attributes or string values.
3985 * Just gather the element top list
3986 */
3987 if (cur->content != NULL) {
3988 parent = cur;
3989 cur = cur->content;
3990 tmp = cur;
3991 while (tmp != NULL) {
3992 tmp->parent = parent;
3993 tmp = tmp->next;
3994 }
3995 continue;
3996 }
3997 }
3998 if (cur == def)
3999 break;
4000 if (cur->next != NULL) {
4001 cur = cur->next;
4002 continue;
4003 }
4004 do {
4005 cur = cur->parent;
4006 if (cur == NULL)
4007 break;
4008 if (cur == def)
4009 return (ret);
4010 if (cur->next != NULL) {
4011 cur = cur->next;
4012 break;
4013 }
4014 } while (cur != NULL);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004015 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004016 return (ret);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004017}
Daniel Veillard4c004142003-10-07 11:33:24 +00004018
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004019/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004020 * xmlRelaxNGCheckChoiceDeterminism:
4021 * @ctxt: a Relax-NG parser context
4022 * @def: the choice definition
4023 *
4024 * Also used to find indeterministic pattern in choice
4025 */
4026static void
4027xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004028 xmlRelaxNGDefinePtr def)
4029{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004030 xmlRelaxNGDefinePtr **list;
4031 xmlRelaxNGDefinePtr cur;
4032 int nbchild = 0, i, j, ret;
4033 int is_nullable = 0;
4034 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004035 xmlHashTablePtr triage = NULL;
4036 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004037
Daniel Veillard4c004142003-10-07 11:33:24 +00004038 if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
4039 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004040
Daniel Veillarde063f482003-03-21 16:53:17 +00004041 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004042 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004043
Daniel Veillardfd573f12003-03-16 17:52:32 +00004044 /*
4045 * Don't run that check in case of error. Infinite recursion
4046 * becomes possible.
4047 */
4048 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004049 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004050
4051 is_nullable = xmlRelaxNGIsNullable(def);
4052
4053 cur = def->content;
4054 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004055 nbchild++;
4056 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004057 }
4058
4059 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004060 sizeof(xmlRelaxNGDefinePtr
4061 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004062 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004063 xmlRngPErrMemory(ctxt, "building choice\n");
4064 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004065 }
4066 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004067 /*
4068 * a bit strong but safe
4069 */
4070 if (is_nullable == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004071 triage = xmlHashCreate(10);
Daniel Veillarde063f482003-03-21 16:53:17 +00004072 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004073 is_triable = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004074 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004075 cur = def->content;
4076 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004077 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4078 if ((list[i] == NULL) || (list[i][0] == NULL)) {
4079 is_triable = 0;
4080 } else if (is_triable == 1) {
4081 xmlRelaxNGDefinePtr *tmp;
4082 int res;
Daniel Veillarde063f482003-03-21 16:53:17 +00004083
Daniel Veillard4c004142003-10-07 11:33:24 +00004084 tmp = list[i];
4085 while ((*tmp != NULL) && (is_triable == 1)) {
4086 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4087 res = xmlHashAddEntry2(triage,
4088 BAD_CAST "#text", NULL,
4089 (void *) cur);
4090 if (res != 0)
4091 is_triable = -1;
4092 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4093 ((*tmp)->name != NULL)) {
4094 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4095 res = xmlHashAddEntry2(triage,
4096 (*tmp)->name, NULL,
4097 (void *) cur);
4098 else
4099 res = xmlHashAddEntry2(triage,
4100 (*tmp)->name, (*tmp)->ns,
4101 (void *) cur);
4102 if (res != 0)
4103 is_triable = -1;
4104 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4105 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4106 res = xmlHashAddEntry2(triage,
4107 BAD_CAST "#any", NULL,
4108 (void *) cur);
4109 else
4110 res = xmlHashAddEntry2(triage,
4111 BAD_CAST "#any", (*tmp)->ns,
4112 (void *) cur);
4113 if (res != 0)
4114 is_triable = -1;
4115 } else {
4116 is_triable = -1;
4117 }
4118 tmp++;
4119 }
4120 }
4121 i++;
4122 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004123 }
4124
Daniel Veillard4c004142003-10-07 11:33:24 +00004125 for (i = 0; i < nbchild; i++) {
4126 if (list[i] == NULL)
4127 continue;
4128 for (j = 0; j < i; j++) {
4129 if (list[j] == NULL)
4130 continue;
4131 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4132 if (ret == 0) {
4133 is_indeterminist = 1;
4134 }
4135 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004136 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004137 for (i = 0; i < nbchild; i++) {
4138 if (list[i] != NULL)
4139 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004140 }
4141
4142 xmlFree(list);
4143 if (is_indeterminist) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004144 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004145 }
Daniel Veillarde063f482003-03-21 16:53:17 +00004146 if (is_triable == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004147 def->dflags |= IS_TRIABLE;
4148 def->data = triage;
Daniel Veillarde063f482003-03-21 16:53:17 +00004149 } else if (triage != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004150 xmlHashFree(triage, NULL);
Daniel Veillarde063f482003-03-21 16:53:17 +00004151 }
4152 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004153}
4154
4155/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004156 * xmlRelaxNGCheckGroupAttrs:
4157 * @ctxt: a Relax-NG parser context
4158 * @def: the group definition
4159 *
4160 * Detects violations of rule 7.3
4161 */
4162static void
4163xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004164 xmlRelaxNGDefinePtr def)
4165{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004166 xmlRelaxNGDefinePtr **list;
4167 xmlRelaxNGDefinePtr cur;
4168 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004169
4170 if ((def == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00004171 ((def->type != XML_RELAXNG_GROUP) &&
4172 (def->type != XML_RELAXNG_ELEMENT)))
4173 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004174
Daniel Veillarde063f482003-03-21 16:53:17 +00004175 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004176 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004177
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004178 /*
4179 * Don't run that check in case of error. Infinite recursion
4180 * becomes possible.
4181 */
4182 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004183 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004184
Daniel Veillardfd573f12003-03-16 17:52:32 +00004185 cur = def->attrs;
4186 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004187 nbchild++;
4188 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004189 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004190 cur = def->content;
4191 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004192 nbchild++;
4193 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004194 }
4195
4196 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004197 sizeof(xmlRelaxNGDefinePtr
4198 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004199 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004200 xmlRngPErrMemory(ctxt, "building group\n");
4201 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004202 }
4203 i = 0;
4204 cur = def->attrs;
4205 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004206 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4207 i++;
4208 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004209 }
4210 cur = def->content;
4211 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004212 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4213 i++;
4214 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004215 }
4216
Daniel Veillard4c004142003-10-07 11:33:24 +00004217 for (i = 0; i < nbchild; i++) {
4218 if (list[i] == NULL)
4219 continue;
4220 for (j = 0; j < i; j++) {
4221 if (list[j] == NULL)
4222 continue;
4223 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4224 if (ret == 0) {
4225 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4226 "Attributes conflicts in group\n", NULL, NULL);
4227 }
4228 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004229 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004230 for (i = 0; i < nbchild; i++) {
4231 if (list[i] != NULL)
4232 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004233 }
4234
4235 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00004236 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004237}
4238
4239/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004240 * xmlRelaxNGComputeInterleaves:
4241 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004242 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00004243 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004244 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00004245 * A lot of work for preprocessing interleave definitions
4246 * is potentially needed to get a decent execution speed at runtime
4247 * - trying to get a total order on the element nodes generated
4248 * by the interleaves, order the list of interleave definitions
4249 * following that order.
4250 * - if <text/> is used to handle mixed content, it is better to
4251 * flag this in the define and simplify the runtime checking
4252 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004253 */
4254static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00004255xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
Daniel Veillard4c004142003-10-07 11:33:24 +00004256 xmlRelaxNGParserCtxtPtr ctxt,
4257 xmlChar * name ATTRIBUTE_UNUSED)
4258{
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004259 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004260
Daniel Veillardfd573f12003-03-16 17:52:32 +00004261 xmlRelaxNGPartitionPtr partitions = NULL;
4262 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4263 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillard4c004142003-10-07 11:33:24 +00004264 int i, j, ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004265 int nbgroups = 0;
4266 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004267 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004268 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004269
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004270 /*
4271 * Don't run that check in case of error. Infinite recursion
4272 * becomes possible.
4273 */
4274 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004275 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004276
Daniel Veillardfd573f12003-03-16 17:52:32 +00004277#ifdef DEBUG_INTERLEAVE
4278 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00004279 "xmlRelaxNGComputeInterleaves(%s)\n", name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004280#endif
4281 cur = def->content;
4282 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004283 nbchild++;
4284 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004285 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004286
Daniel Veillardfd573f12003-03-16 17:52:32 +00004287#ifdef DEBUG_INTERLEAVE
4288 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
4289#endif
4290 groups = (xmlRelaxNGInterleaveGroupPtr *)
Daniel Veillard4c004142003-10-07 11:33:24 +00004291 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004292 if (groups == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004293 goto error;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004294 cur = def->content;
4295 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004296 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4297 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4298 if (groups[nbgroups] == NULL)
4299 goto error;
4300 if (cur->type == XML_RELAXNG_TEXT)
4301 is_mixed++;
4302 groups[nbgroups]->rule = cur;
4303 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4304 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4305 nbgroups++;
4306 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004307 }
4308#ifdef DEBUG_INTERLEAVE
4309 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4310#endif
4311
4312 /*
4313 * Let's check that all rules makes a partitions according to 7.4
4314 */
4315 partitions = (xmlRelaxNGPartitionPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00004316 xmlMalloc(sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004317 if (partitions == NULL)
4318 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004319 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004320 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004321 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillard4c004142003-10-07 11:33:24 +00004322 for (i = 0; i < nbgroups; i++) {
4323 group = groups[i];
4324 for (j = i + 1; j < nbgroups; j++) {
4325 if (groups[j] == NULL)
4326 continue;
4327
4328 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4329 groups[j]->defs);
4330 if (ret == 0) {
4331 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4332 "Element or text conflicts in interleave\n",
4333 NULL, NULL);
4334 }
4335 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4336 groups[j]->attrs);
4337 if (ret == 0) {
4338 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4339 "Attributes conflicts in interleave\n", NULL,
4340 NULL);
4341 }
4342 }
4343 tmp = group->defs;
4344 if ((tmp != NULL) && (*tmp != NULL)) {
4345 while (*tmp != NULL) {
4346 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4347 res = xmlHashAddEntry2(partitions->triage,
4348 BAD_CAST "#text", NULL,
4349 (void *) (long) (i + 1));
4350 if (res != 0)
4351 is_determinist = -1;
4352 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4353 ((*tmp)->name != NULL)) {
4354 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4355 res = xmlHashAddEntry2(partitions->triage,
4356 (*tmp)->name, NULL,
4357 (void *) (long) (i + 1));
4358 else
4359 res = xmlHashAddEntry2(partitions->triage,
4360 (*tmp)->name, (*tmp)->ns,
4361 (void *) (long) (i + 1));
4362 if (res != 0)
4363 is_determinist = -1;
4364 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4365 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4366 res = xmlHashAddEntry2(partitions->triage,
4367 BAD_CAST "#any", NULL,
4368 (void *) (long) (i + 1));
4369 else
4370 res = xmlHashAddEntry2(partitions->triage,
4371 BAD_CAST "#any", (*tmp)->ns,
4372 (void *) (long) (i + 1));
4373 if ((*tmp)->nameClass != NULL)
4374 is_determinist = 2;
4375 if (res != 0)
4376 is_determinist = -1;
4377 } else {
4378 is_determinist = -1;
4379 }
4380 tmp++;
4381 }
4382 } else {
4383 is_determinist = 0;
4384 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004385 }
4386 partitions->groups = groups;
4387
4388 /*
4389 * and save the partition list back in the def
4390 */
4391 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004392 if (is_mixed != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004393 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004394 if (is_determinist == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00004395 partitions->flags = IS_DETERMINIST;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004396 if (is_determinist == 2)
Daniel Veillard4c004142003-10-07 11:33:24 +00004397 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004398 return;
4399
Daniel Veillard4c004142003-10-07 11:33:24 +00004400 error:
4401 xmlRngPErrMemory(ctxt, "in interleave computation\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004402 if (groups != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004403 for (i = 0; i < nbgroups; i++)
4404 if (groups[i] != NULL) {
4405 if (groups[i]->defs != NULL)
4406 xmlFree(groups[i]->defs);
4407 xmlFree(groups[i]);
4408 }
4409 xmlFree(groups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004410 }
4411 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004412}
4413
4414/**
4415 * xmlRelaxNGParseInterleave:
4416 * @ctxt: a Relax-NG parser context
4417 * @node: the data node.
4418 *
4419 * parse the content of a RelaxNG interleave node.
4420 *
4421 * Returns the definition pointer or NULL in case of error
4422 */
4423static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004424xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4425{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004426 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004427 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004428 xmlNodePtr child;
4429
Daniel Veillardfd573f12003-03-16 17:52:32 +00004430 def = xmlRelaxNGNewDefine(ctxt, node);
4431 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004432 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004433 }
4434 def->type = XML_RELAXNG_INTERLEAVE;
4435
4436 if (ctxt->interleaves == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004437 ctxt->interleaves = xmlHashCreate(10);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004438 if (ctxt->interleaves == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004439 xmlRngPErrMemory(ctxt, "create interleaves\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004440 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004441 char name[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00004442
Daniel Veillard4c004142003-10-07 11:33:24 +00004443 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4444 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4445 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4446 "Failed to add %s to hash table\n",
4447 (const xmlChar *) name, NULL);
4448 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004449 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004450 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004451 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004452 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4453 "Element interleave is empty\n", NULL, NULL);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004454 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004455 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004456 if (IS_RELAXNG(child, "element")) {
4457 cur = xmlRelaxNGParseElement(ctxt, child);
4458 } else {
4459 cur = xmlRelaxNGParsePattern(ctxt, child);
4460 }
4461 if (cur != NULL) {
4462 cur->parent = def;
4463 if (last == NULL) {
4464 def->content = last = cur;
4465 } else {
4466 last->next = cur;
4467 last = cur;
4468 }
4469 }
4470 child = child->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004471 }
4472
Daniel Veillard4c004142003-10-07 11:33:24 +00004473 return (def);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004474}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004475
4476/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004477 * xmlRelaxNGParseInclude:
4478 * @ctxt: a Relax-NG parser context
4479 * @node: the include node
4480 *
4481 * Integrate the content of an include node in the current grammar
4482 *
4483 * Returns 0 in case of success or -1 in case of error
4484 */
4485static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004486xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4487{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004488 xmlRelaxNGIncludePtr incl;
4489 xmlNodePtr root;
4490 int ret = 0, tmp;
4491
Daniel Veillard807daf82004-02-22 22:13:27 +00004492 incl = node->psvi;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004493 if (incl == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004494 xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4495 "Include node has no data\n", NULL, NULL);
4496 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004497 }
4498 root = xmlDocGetRootElement(incl->doc);
4499 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004500 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4501 NULL, NULL);
4502 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004503 }
4504 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004505 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4506 "Include document root is not a grammar\n", NULL, NULL);
4507 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004508 }
4509
4510 /*
4511 * Merge the definition from both the include and the internal list
4512 */
4513 if (root->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004514 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4515 if (tmp != 0)
4516 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004517 }
4518 if (node->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004519 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4520 if (tmp != 0)
4521 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004522 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004523 return (ret);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004524}
4525
4526/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004527 * xmlRelaxNGParseDefine:
4528 * @ctxt: a Relax-NG parser context
4529 * @node: the define node
4530 *
4531 * parse the content of a RelaxNG define element node.
4532 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004533 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004534 */
4535static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004536xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4537{
Daniel Veillard276be4a2003-01-24 01:03:34 +00004538 xmlChar *name;
4539 int ret = 0, tmp;
4540 xmlRelaxNGDefinePtr def;
4541 const xmlChar *olddefine;
4542
4543 name = xmlGetProp(node, BAD_CAST "name");
4544 if (name == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004545 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4546 "define has no name\n", NULL, NULL);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004547 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004548 xmlRelaxNGNormExtSpace(name);
4549 if (xmlValidateNCName(name, 0)) {
4550 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4551 "define name '%s' is not an NCName\n", name, NULL);
4552 }
4553 def = xmlRelaxNGNewDefine(ctxt, node);
4554 if (def == NULL) {
4555 xmlFree(name);
4556 return (-1);
4557 }
4558 def->type = XML_RELAXNG_DEF;
4559 def->name = name;
4560 if (node->children == NULL) {
4561 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4562 "define has no children\n", NULL, NULL);
4563 } else {
4564 olddefine = ctxt->define;
4565 ctxt->define = name;
4566 def->content =
4567 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4568 ctxt->define = olddefine;
4569 }
4570 if (ctxt->grammar->defs == NULL)
4571 ctxt->grammar->defs = xmlHashCreate(10);
4572 if (ctxt->grammar->defs == NULL) {
4573 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4574 "Could not create definition hash\n", NULL, NULL);
4575 ret = -1;
4576 } else {
4577 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4578 if (tmp < 0) {
4579 xmlRelaxNGDefinePtr prev;
Daniel Veillard154877e2003-01-30 12:17:05 +00004580
Daniel Veillard4c004142003-10-07 11:33:24 +00004581 prev = xmlHashLookup(ctxt->grammar->defs, name);
4582 if (prev == NULL) {
4583 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4584 "Internal error on define aggregation of %s\n",
4585 name, NULL);
4586 ret = -1;
4587 } else {
4588 while (prev->nextHash != NULL)
4589 prev = prev->nextHash;
4590 prev->nextHash = def;
4591 }
4592 }
4593 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004594 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004595 return (ret);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004596}
4597
4598/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004599 * xmlRelaxNGProcessExternalRef:
4600 * @ctxt: the parser context
4601 * @node: the externlRef node
4602 *
4603 * Process and compile an externlRef node
4604 *
4605 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4606 */
4607static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004608xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4609{
Daniel Veillardfebcca42003-02-16 15:44:18 +00004610 xmlRelaxNGDocumentPtr docu;
4611 xmlNodePtr root, tmp;
4612 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004613 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004614 xmlRelaxNGDefinePtr def;
4615
Daniel Veillard807daf82004-02-22 22:13:27 +00004616 docu = node->psvi;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004617 if (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004618 def = xmlRelaxNGNewDefine(ctxt, node);
4619 if (def == NULL)
4620 return (NULL);
4621 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004622
Daniel Veillard4c004142003-10-07 11:33:24 +00004623 if (docu->content == NULL) {
4624 /*
4625 * Then do the parsing for good
4626 */
4627 root = xmlDocGetRootElement(docu->doc);
4628 if (root == NULL) {
4629 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
4630 "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
4631 NULL);
4632 return (NULL);
4633 }
4634 /*
4635 * ns transmission rules
4636 */
4637 ns = xmlGetProp(root, BAD_CAST "ns");
4638 if (ns == NULL) {
4639 tmp = node;
4640 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
4641 ns = xmlGetProp(tmp, BAD_CAST "ns");
4642 if (ns != NULL) {
4643 break;
4644 }
4645 tmp = tmp->parent;
4646 }
4647 if (ns != NULL) {
4648 xmlSetProp(root, BAD_CAST "ns", ns);
4649 newNs = 1;
4650 xmlFree(ns);
4651 }
4652 } else {
4653 xmlFree(ns);
4654 }
Daniel Veillardfebcca42003-02-16 15:44:18 +00004655
Daniel Veillard4c004142003-10-07 11:33:24 +00004656 /*
4657 * Parsing to get a precompiled schemas.
4658 */
4659 oldflags = ctxt->flags;
4660 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4661 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4662 ctxt->flags = oldflags;
4663 if ((docu->schema != NULL) &&
4664 (docu->schema->topgrammar != NULL)) {
4665 docu->content = docu->schema->topgrammar->start;
4666 }
4667
4668 /*
4669 * the externalRef may be reused in a different ns context
4670 */
4671 if (newNs == 1) {
4672 xmlUnsetProp(root, BAD_CAST "ns");
4673 }
4674 }
4675 def->content = docu->content;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004676 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004677 def = NULL;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004678 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004679 return (def);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004680}
4681
4682/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004683 * xmlRelaxNGParsePattern:
4684 * @ctxt: a Relax-NG parser context
4685 * @node: the pattern node.
4686 *
4687 * parse the content of a RelaxNG pattern node.
4688 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004689 * Returns the definition pointer or NULL in case of error or if no
4690 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004691 */
4692static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004693xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4694{
Daniel Veillard6eadf632003-01-23 18:29:16 +00004695 xmlRelaxNGDefinePtr def = NULL;
4696
Daniel Veillardd2298792003-02-14 16:54:11 +00004697 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004698 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004699 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004700 if (IS_RELAXNG(node, "element")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004701 def = xmlRelaxNGParseElement(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004702 } else if (IS_RELAXNG(node, "attribute")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004703 def = xmlRelaxNGParseAttribute(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004704 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004705 def = xmlRelaxNGNewDefine(ctxt, node);
4706 if (def == NULL)
4707 return (NULL);
4708 def->type = XML_RELAXNG_EMPTY;
4709 if (node->children != NULL) {
4710 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
4711 "empty: had a child node\n", NULL, NULL);
4712 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004713 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004714 def = xmlRelaxNGNewDefine(ctxt, node);
4715 if (def == NULL)
4716 return (NULL);
4717 def->type = XML_RELAXNG_TEXT;
4718 if (node->children != NULL) {
4719 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
4720 "text: had a child node\n", NULL, NULL);
4721 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004722 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004723 def = xmlRelaxNGNewDefine(ctxt, node);
4724 if (def == NULL)
4725 return (NULL);
4726 def->type = XML_RELAXNG_ZEROORMORE;
4727 if (node->children == NULL) {
4728 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4729 "Element %s is empty\n", node->name, NULL);
4730 } else {
4731 def->content =
4732 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4733 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004734 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004735 def = xmlRelaxNGNewDefine(ctxt, node);
4736 if (def == NULL)
4737 return (NULL);
4738 def->type = XML_RELAXNG_ONEORMORE;
4739 if (node->children == NULL) {
4740 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4741 "Element %s is empty\n", node->name, NULL);
4742 } else {
4743 def->content =
4744 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4745 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004746 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004747 def = xmlRelaxNGNewDefine(ctxt, node);
4748 if (def == NULL)
4749 return (NULL);
4750 def->type = XML_RELAXNG_OPTIONAL;
4751 if (node->children == NULL) {
4752 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4753 "Element %s is empty\n", node->name, NULL);
4754 } else {
4755 def->content =
4756 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4757 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004758 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004759 def = xmlRelaxNGNewDefine(ctxt, node);
4760 if (def == NULL)
4761 return (NULL);
4762 def->type = XML_RELAXNG_CHOICE;
4763 if (node->children == NULL) {
4764 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4765 "Element %s is empty\n", node->name, NULL);
4766 } else {
4767 def->content =
4768 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4769 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004770 } else if (IS_RELAXNG(node, "group")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004771 def = xmlRelaxNGNewDefine(ctxt, node);
4772 if (def == NULL)
4773 return (NULL);
4774 def->type = XML_RELAXNG_GROUP;
4775 if (node->children == NULL) {
4776 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4777 "Element %s is empty\n", node->name, NULL);
4778 } else {
4779 def->content =
4780 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4781 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004782 } else if (IS_RELAXNG(node, "ref")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004783 def = xmlRelaxNGNewDefine(ctxt, node);
4784 if (def == NULL)
4785 return (NULL);
4786 def->type = XML_RELAXNG_REF;
4787 def->name = xmlGetProp(node, BAD_CAST "name");
4788 if (def->name == NULL) {
4789 xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
4790 NULL, NULL);
4791 } else {
4792 xmlRelaxNGNormExtSpace(def->name);
4793 if (xmlValidateNCName(def->name, 0)) {
4794 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
4795 "ref name '%s' is not an NCName\n", def->name,
4796 NULL);
4797 }
4798 }
4799 if (node->children != NULL) {
4800 xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
4801 NULL, NULL);
4802 }
4803 if (ctxt->grammar->refs == NULL)
4804 ctxt->grammar->refs = xmlHashCreate(10);
4805 if (ctxt->grammar->refs == NULL) {
4806 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4807 "Could not create references hash\n", NULL, NULL);
4808 def = NULL;
4809 } else {
4810 int tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004811
Daniel Veillard4c004142003-10-07 11:33:24 +00004812 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4813 if (tmp < 0) {
4814 xmlRelaxNGDefinePtr prev;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004815
Daniel Veillard4c004142003-10-07 11:33:24 +00004816 prev = (xmlRelaxNGDefinePtr)
4817 xmlHashLookup(ctxt->grammar->refs, def->name);
4818 if (prev == NULL) {
4819 if (def->name != NULL) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004820 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4821 "Error refs definitions '%s'\n",
4822 def->name, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004823 } else {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004824 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4825 "Error refs definitions\n",
4826 NULL, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004827 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004828 def = NULL;
4829 } else {
4830 def->nextHash = prev->nextHash;
4831 prev->nextHash = def;
4832 }
4833 }
4834 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004835 } else if (IS_RELAXNG(node, "data")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004836 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004837 } else if (IS_RELAXNG(node, "value")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004838 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004839 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004840 def = xmlRelaxNGNewDefine(ctxt, node);
4841 if (def == NULL)
4842 return (NULL);
4843 def->type = XML_RELAXNG_LIST;
4844 if (node->children == NULL) {
4845 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4846 "Element %s is empty\n", node->name, NULL);
4847 } else {
4848 def->content =
4849 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4850 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004851 } else if (IS_RELAXNG(node, "interleave")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004852 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004853 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004854 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004855 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004856 def = xmlRelaxNGNewDefine(ctxt, node);
4857 if (def == NULL)
4858 return (NULL);
4859 def->type = XML_RELAXNG_NOT_ALLOWED;
4860 if (node->children != NULL) {
4861 xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
4862 "xmlRelaxNGParse: notAllowed element is not empty\n",
4863 NULL, NULL);
4864 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004865 } else if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004866 xmlRelaxNGGrammarPtr grammar, old;
4867 xmlRelaxNGGrammarPtr oldparent;
Daniel Veillard419a7682003-02-03 23:22:49 +00004868
Daniel Veillardc482e262003-02-26 14:48:48 +00004869#ifdef DEBUG_GRAMMAR
Daniel Veillard4c004142003-10-07 11:33:24 +00004870 xmlGenericError(xmlGenericErrorContext,
4871 "Found <grammar> pattern\n");
Daniel Veillardc482e262003-02-26 14:48:48 +00004872#endif
4873
Daniel Veillard4c004142003-10-07 11:33:24 +00004874 oldparent = ctxt->parentgrammar;
4875 old = ctxt->grammar;
4876 ctxt->parentgrammar = old;
4877 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4878 if (old != NULL) {
4879 ctxt->grammar = old;
4880 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004881#if 0
Daniel Veillard4c004142003-10-07 11:33:24 +00004882 if (grammar != NULL) {
4883 grammar->next = old->next;
4884 old->next = grammar;
4885 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004886#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00004887 }
4888 if (grammar != NULL)
4889 def = grammar->start;
4890 else
4891 def = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00004892 } else if (IS_RELAXNG(node, "parentRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004893 if (ctxt->parentgrammar == NULL) {
4894 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
4895 "Use of parentRef without a parent grammar\n", NULL,
4896 NULL);
4897 return (NULL);
4898 }
4899 def = xmlRelaxNGNewDefine(ctxt, node);
4900 if (def == NULL)
4901 return (NULL);
4902 def->type = XML_RELAXNG_PARENTREF;
4903 def->name = xmlGetProp(node, BAD_CAST "name");
4904 if (def->name == NULL) {
4905 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
4906 "parentRef has no name\n", NULL, NULL);
4907 } else {
4908 xmlRelaxNGNormExtSpace(def->name);
4909 if (xmlValidateNCName(def->name, 0)) {
4910 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
4911 "parentRef name '%s' is not an NCName\n",
4912 def->name, NULL);
4913 }
4914 }
4915 if (node->children != NULL) {
4916 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
4917 "parentRef is not empty\n", NULL, NULL);
4918 }
4919 if (ctxt->parentgrammar->refs == NULL)
4920 ctxt->parentgrammar->refs = xmlHashCreate(10);
4921 if (ctxt->parentgrammar->refs == NULL) {
4922 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4923 "Could not create references hash\n", NULL, NULL);
4924 def = NULL;
4925 } else if (def->name != NULL) {
4926 int tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +00004927
Daniel Veillard4c004142003-10-07 11:33:24 +00004928 tmp =
4929 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4930 if (tmp < 0) {
4931 xmlRelaxNGDefinePtr prev;
Daniel Veillard419a7682003-02-03 23:22:49 +00004932
Daniel Veillard4c004142003-10-07 11:33:24 +00004933 prev = (xmlRelaxNGDefinePtr)
4934 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4935 if (prev == NULL) {
4936 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4937 "Internal error parentRef definitions '%s'\n",
4938 def->name, NULL);
4939 def = NULL;
4940 } else {
4941 def->nextHash = prev->nextHash;
4942 prev->nextHash = def;
4943 }
4944 }
4945 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004946 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004947 if (node->children == NULL) {
4948 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
4949 NULL, NULL);
4950 def = NULL;
4951 } else {
4952 def = xmlRelaxNGParseInterleave(ctxt, node);
4953 if (def != NULL) {
4954 xmlRelaxNGDefinePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004955
Daniel Veillard4c004142003-10-07 11:33:24 +00004956 if ((def->content != NULL) && (def->content->next != NULL)) {
4957 tmp = xmlRelaxNGNewDefine(ctxt, node);
4958 if (tmp != NULL) {
4959 tmp->type = XML_RELAXNG_GROUP;
4960 tmp->content = def->content;
4961 def->content = tmp;
4962 }
4963 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004964
Daniel Veillard4c004142003-10-07 11:33:24 +00004965 tmp = xmlRelaxNGNewDefine(ctxt, node);
4966 if (tmp == NULL)
4967 return (def);
4968 tmp->type = XML_RELAXNG_TEXT;
4969 tmp->next = def->content;
4970 def->content = tmp;
4971 }
4972 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004973 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004974 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
4975 "Unexpected node %s is not a pattern\n", node->name,
4976 NULL);
4977 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004978 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004979 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004980}
4981
4982/**
4983 * xmlRelaxNGParseAttribute:
4984 * @ctxt: a Relax-NG parser context
4985 * @node: the element node
4986 *
4987 * parse the content of a RelaxNG attribute node.
4988 *
4989 * Returns the definition pointer or NULL in case of error.
4990 */
4991static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004992xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4993{
Daniel Veillardd2298792003-02-14 16:54:11 +00004994 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004995 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004996 int old_flags;
4997
Daniel Veillardfd573f12003-03-16 17:52:32 +00004998 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004999 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005000 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005001 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005002 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005003 child = node->children;
5004 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005005 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
5006 "xmlRelaxNGParseattribute: attribute has no children\n",
5007 NULL, NULL);
5008 return (ret);
5009 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005010 old_flags = ctxt->flags;
5011 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005012 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5013 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005014 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005015
Daniel Veillardd2298792003-02-14 16:54:11 +00005016 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005017 cur = xmlRelaxNGParsePattern(ctxt, child);
5018 if (cur != NULL) {
5019 switch (cur->type) {
5020 case XML_RELAXNG_EMPTY:
5021 case XML_RELAXNG_NOT_ALLOWED:
5022 case XML_RELAXNG_TEXT:
5023 case XML_RELAXNG_ELEMENT:
5024 case XML_RELAXNG_DATATYPE:
5025 case XML_RELAXNG_VALUE:
5026 case XML_RELAXNG_LIST:
5027 case XML_RELAXNG_REF:
5028 case XML_RELAXNG_PARENTREF:
5029 case XML_RELAXNG_EXTERNALREF:
5030 case XML_RELAXNG_DEF:
5031 case XML_RELAXNG_ONEORMORE:
5032 case XML_RELAXNG_ZEROORMORE:
5033 case XML_RELAXNG_OPTIONAL:
5034 case XML_RELAXNG_CHOICE:
5035 case XML_RELAXNG_GROUP:
5036 case XML_RELAXNG_INTERLEAVE:
5037 case XML_RELAXNG_ATTRIBUTE:
5038 ret->content = cur;
5039 cur->parent = ret;
5040 break;
5041 case XML_RELAXNG_START:
5042 case XML_RELAXNG_PARAM:
5043 case XML_RELAXNG_EXCEPT:
5044 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
5045 "attribute has invalid content\n", NULL,
5046 NULL);
5047 break;
5048 case XML_RELAXNG_NOOP:
5049 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
5050 "RNG Internal error, noop found in attribute\n",
5051 NULL, NULL);
5052 break;
5053 }
5054 }
5055 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005056 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005057 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005058 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
5059 "attribute has multiple children\n", NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005060 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005061 ctxt->flags = old_flags;
Daniel Veillard4c004142003-10-07 11:33:24 +00005062 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005063}
5064
5065/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005066 * xmlRelaxNGParseExceptNameClass:
5067 * @ctxt: a Relax-NG parser context
5068 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00005069 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005070 *
5071 * parse the content of a RelaxNG nameClass node.
5072 *
5073 * Returns the definition pointer or NULL in case of error.
5074 */
5075static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00005076xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005077 xmlNodePtr node, int attr)
5078{
Daniel Veillard144fae12003-02-03 13:17:57 +00005079 xmlRelaxNGDefinePtr ret, cur, last = NULL;
5080 xmlNodePtr child;
5081
Daniel Veillardd2298792003-02-14 16:54:11 +00005082 if (!IS_RELAXNG(node, "except")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005083 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
5084 "Expecting an except node\n", NULL, NULL);
5085 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005086 }
5087 if (node->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005088 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
5089 "exceptNameClass allows only a single except node\n",
5090 NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005091 }
Daniel Veillard144fae12003-02-03 13:17:57 +00005092 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005093 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
5094 NULL, NULL);
5095 return (NULL);
Daniel Veillard144fae12003-02-03 13:17:57 +00005096 }
5097
Daniel Veillardfd573f12003-03-16 17:52:32 +00005098 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00005099 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005100 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005101 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00005102 child = node->children;
5103 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005104 cur = xmlRelaxNGNewDefine(ctxt, child);
5105 if (cur == NULL)
5106 break;
5107 if (attr)
5108 cur->type = XML_RELAXNG_ATTRIBUTE;
5109 else
5110 cur->type = XML_RELAXNG_ELEMENT;
5111
Daniel Veillard419a7682003-02-03 23:22:49 +00005112 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005113 if (last == NULL) {
5114 ret->content = cur;
5115 } else {
5116 last->next = cur;
5117 }
5118 last = cur;
5119 }
5120 child = child->next;
Daniel Veillard144fae12003-02-03 13:17:57 +00005121 }
5122
Daniel Veillard4c004142003-10-07 11:33:24 +00005123 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005124}
5125
5126/**
5127 * xmlRelaxNGParseNameClass:
5128 * @ctxt: a Relax-NG parser context
5129 * @node: the nameClass node
5130 * @def: the current definition
5131 *
5132 * parse the content of a RelaxNG nameClass node.
5133 *
5134 * Returns the definition pointer or NULL in case of error.
5135 */
5136static xmlRelaxNGDefinePtr
5137xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillard4c004142003-10-07 11:33:24 +00005138 xmlRelaxNGDefinePtr def)
5139{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005140 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005141 xmlChar *val;
5142
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005143 ret = def;
Daniel Veillard4c004142003-10-07 11:33:24 +00005144 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005145 (IS_RELAXNG(node, "nsName"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005146 if ((def->type != XML_RELAXNG_ELEMENT) &&
5147 (def->type != XML_RELAXNG_ATTRIBUTE)) {
5148 ret = xmlRelaxNGNewDefine(ctxt, node);
5149 if (ret == NULL)
5150 return (NULL);
5151 ret->parent = def;
5152 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5153 ret->type = XML_RELAXNG_ATTRIBUTE;
5154 else
5155 ret->type = XML_RELAXNG_ELEMENT;
5156 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005157 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005158 if (IS_RELAXNG(node, "name")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005159 val = xmlNodeGetContent(node);
5160 xmlRelaxNGNormExtSpace(val);
5161 if (xmlValidateNCName(val, 0)) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005162 if (node->parent != NULL)
5163 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5164 "Element %s name '%s' is not an NCName\n",
5165 node->parent->name, val);
5166 else
5167 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5168 "name '%s' is not an NCName\n",
5169 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005170 }
5171 ret->name = val;
5172 val = xmlGetProp(node, BAD_CAST "ns");
5173 ret->ns = val;
5174 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5175 (val != NULL) &&
5176 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005177 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
Daniel Veillard4c004142003-10-07 11:33:24 +00005178 "Attribute with namespace '%s' is not allowed\n",
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005179 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005180 }
5181 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5182 (val != NULL) &&
5183 (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005184 xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
5185 "Attribute with QName 'xmlns' is not allowed\n",
5186 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005187 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005188 } else if (IS_RELAXNG(node, "anyName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005189 ret->name = NULL;
5190 ret->ns = NULL;
5191 if (node->children != NULL) {
5192 ret->nameClass =
5193 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5194 (def->type ==
5195 XML_RELAXNG_ATTRIBUTE));
5196 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005197 } else if (IS_RELAXNG(node, "nsName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005198 ret->name = NULL;
5199 ret->ns = xmlGetProp(node, BAD_CAST "ns");
5200 if (ret->ns == NULL) {
5201 xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
5202 "nsName has no ns attribute\n", NULL, NULL);
5203 }
5204 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5205 (ret->ns != NULL) &&
5206 (xmlStrEqual
5207 (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5208 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5209 "Attribute with namespace '%s' is not allowed\n",
5210 ret->ns, NULL);
5211 }
5212 if (node->children != NULL) {
5213 ret->nameClass =
5214 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5215 (def->type ==
5216 XML_RELAXNG_ATTRIBUTE));
5217 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005218 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005219 xmlNodePtr child;
5220 xmlRelaxNGDefinePtr last = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005221
Daniel Veillard4c004142003-10-07 11:33:24 +00005222 ret = xmlRelaxNGNewDefine(ctxt, node);
5223 if (ret == NULL)
5224 return (NULL);
5225 ret->parent = def;
5226 ret->type = XML_RELAXNG_CHOICE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005227
Daniel Veillard4c004142003-10-07 11:33:24 +00005228 if (node->children == NULL) {
5229 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
5230 "Element choice is empty\n", NULL, NULL);
5231 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005232
Daniel Veillard4c004142003-10-07 11:33:24 +00005233 child = node->children;
5234 while (child != NULL) {
5235 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5236 if (tmp != NULL) {
5237 if (last == NULL) {
5238 last = ret->nameClass = tmp;
5239 } else {
5240 last->next = tmp;
5241 last = tmp;
5242 }
5243 }
5244 child = child->next;
5245 }
5246 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005247 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005248 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
5249 "expecting name, anyName, nsName or choice : got %s\n",
5250 node->name, NULL);
5251 return (NULL);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005252 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005253 if (ret != def) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005254 if (def->nameClass == NULL) {
5255 def->nameClass = ret;
5256 } else {
5257 tmp = def->nameClass;
5258 while (tmp->next != NULL) {
5259 tmp = tmp->next;
5260 }
5261 tmp->next = ret;
5262 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005263 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005264 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005265}
5266
5267/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005268 * xmlRelaxNGParseElement:
5269 * @ctxt: a Relax-NG parser context
5270 * @node: the element node
5271 *
5272 * parse the content of a RelaxNG element node.
5273 *
5274 * Returns the definition pointer or NULL in case of error.
5275 */
5276static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005277xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5278{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005279 xmlRelaxNGDefinePtr ret, cur, last;
5280 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005281 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005282
Daniel Veillardfd573f12003-03-16 17:52:32 +00005283 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005284 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005285 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005286 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005287 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005288 child = node->children;
5289 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005290 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
5291 "xmlRelaxNGParseElement: element has no children\n",
5292 NULL, NULL);
5293 return (ret);
5294 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005295 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5296 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005297 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005298
Daniel Veillard6eadf632003-01-23 18:29:16 +00005299 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005300 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
5301 "xmlRelaxNGParseElement: element has no content\n",
5302 NULL, NULL);
5303 return (ret);
5304 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005305 olddefine = ctxt->define;
5306 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005307 last = NULL;
5308 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005309 cur = xmlRelaxNGParsePattern(ctxt, child);
5310 if (cur != NULL) {
5311 cur->parent = ret;
5312 switch (cur->type) {
5313 case XML_RELAXNG_EMPTY:
5314 case XML_RELAXNG_NOT_ALLOWED:
5315 case XML_RELAXNG_TEXT:
5316 case XML_RELAXNG_ELEMENT:
5317 case XML_RELAXNG_DATATYPE:
5318 case XML_RELAXNG_VALUE:
5319 case XML_RELAXNG_LIST:
5320 case XML_RELAXNG_REF:
5321 case XML_RELAXNG_PARENTREF:
5322 case XML_RELAXNG_EXTERNALREF:
5323 case XML_RELAXNG_DEF:
5324 case XML_RELAXNG_ZEROORMORE:
5325 case XML_RELAXNG_ONEORMORE:
5326 case XML_RELAXNG_OPTIONAL:
5327 case XML_RELAXNG_CHOICE:
5328 case XML_RELAXNG_GROUP:
5329 case XML_RELAXNG_INTERLEAVE:
5330 if (last == NULL) {
5331 ret->content = last = cur;
5332 } else {
5333 if ((last->type == XML_RELAXNG_ELEMENT) &&
5334 (ret->content == last)) {
5335 ret->content = xmlRelaxNGNewDefine(ctxt, node);
5336 if (ret->content != NULL) {
5337 ret->content->type = XML_RELAXNG_GROUP;
5338 ret->content->content = last;
5339 } else {
5340 ret->content = last;
5341 }
5342 }
5343 last->next = cur;
5344 last = cur;
5345 }
5346 break;
5347 case XML_RELAXNG_ATTRIBUTE:
5348 cur->next = ret->attrs;
5349 ret->attrs = cur;
5350 break;
5351 case XML_RELAXNG_START:
5352 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5353 "RNG Internal error, start found in element\n",
5354 NULL, NULL);
5355 break;
5356 case XML_RELAXNG_PARAM:
5357 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5358 "RNG Internal error, param found in element\n",
5359 NULL, NULL);
5360 break;
5361 case XML_RELAXNG_EXCEPT:
5362 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5363 "RNG Internal error, except found in element\n",
5364 NULL, NULL);
5365 break;
5366 case XML_RELAXNG_NOOP:
5367 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5368 "RNG Internal error, noop found in element\n",
5369 NULL, NULL);
5370 break;
5371 }
5372 }
5373 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005374 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005375 ctxt->define = olddefine;
Daniel Veillard4c004142003-10-07 11:33:24 +00005376 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005377}
5378
5379/**
5380 * xmlRelaxNGParsePatterns:
5381 * @ctxt: a Relax-NG parser context
5382 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005383 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005384 *
5385 * parse the content of a RelaxNG start node.
5386 *
5387 * Returns the definition pointer or NULL in case of error.
5388 */
5389static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005390xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
Daniel Veillard4c004142003-10-07 11:33:24 +00005391 int group)
5392{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005393 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005394
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005395 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005396 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005397 if (IS_RELAXNG(nodes, "element")) {
5398 cur = xmlRelaxNGParseElement(ctxt, nodes);
5399 if (def == NULL) {
5400 def = last = cur;
5401 } else {
5402 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5403 (def == last)) {
5404 def = xmlRelaxNGNewDefine(ctxt, nodes);
5405 def->type = XML_RELAXNG_GROUP;
5406 def->content = last;
5407 }
5408 last->next = cur;
5409 last = cur;
5410 }
5411 cur->parent = parent;
5412 } else {
5413 cur = xmlRelaxNGParsePattern(ctxt, nodes);
5414 if (cur != NULL) {
5415 if (def == NULL) {
5416 def = last = cur;
5417 } else {
5418 last->next = cur;
5419 last = cur;
5420 }
5421 }
5422 }
5423 nodes = nodes->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005424 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005425 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005426}
5427
5428/**
5429 * xmlRelaxNGParseStart:
5430 * @ctxt: a Relax-NG parser context
5431 * @nodes: start children nodes
5432 *
5433 * parse the content of a RelaxNG start node.
5434 *
5435 * Returns 0 in case of success, -1 in case of error
5436 */
5437static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005438xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5439{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005440 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005441 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005442
Daniel Veillardd2298792003-02-14 16:54:11 +00005443 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005444 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
5445 NULL, NULL);
5446 return (-1);
Daniel Veillardd2298792003-02-14 16:54:11 +00005447 }
5448 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005449 def = xmlRelaxNGNewDefine(ctxt, nodes);
5450 if (def == NULL)
5451 return (-1);
5452 def->type = XML_RELAXNG_EMPTY;
5453 if (nodes->children != NULL) {
5454 xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
5455 "element empty is not empty\n", NULL, NULL);
5456 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005457 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005458 def = xmlRelaxNGNewDefine(ctxt, nodes);
5459 if (def == NULL)
5460 return (-1);
5461 def->type = XML_RELAXNG_NOT_ALLOWED;
5462 if (nodes->children != NULL) {
5463 xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5464 "element notAllowed is not empty\n", NULL, NULL);
5465 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005466 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005467 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005468 }
5469 if (ctxt->grammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005470 last = ctxt->grammar->start;
5471 while (last->next != NULL)
5472 last = last->next;
5473 last->next = def;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005474 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005475 ctxt->grammar->start = def;
Daniel Veillardd2298792003-02-14 16:54:11 +00005476 }
5477 nodes = nodes->next;
5478 if (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005479 xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
5480 "start more than one children\n", NULL, NULL);
5481 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005482 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005483 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005484}
5485
5486/**
5487 * xmlRelaxNGParseGrammarContent:
5488 * @ctxt: a Relax-NG parser context
5489 * @nodes: grammar children nodes
5490 *
5491 * parse the content of a RelaxNG grammar node.
5492 *
5493 * Returns 0 in case of success, -1 in case of error
5494 */
5495static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005496xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
5497 xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005498{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005499 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005500
5501 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005502 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
5503 "grammar has no children\n", NULL, NULL);
5504 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005505 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005506 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005507 if (IS_RELAXNG(nodes, "start")) {
5508 if (nodes->children == NULL) {
5509 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
5510 "start has no children\n", NULL, NULL);
5511 } else {
5512 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5513 if (tmp != 0)
5514 ret = -1;
5515 }
5516 } else if (IS_RELAXNG(nodes, "define")) {
5517 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5518 if (tmp != 0)
5519 ret = -1;
5520 } else if (IS_RELAXNG(nodes, "include")) {
5521 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5522 if (tmp != 0)
5523 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005524 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005525 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
5526 "grammar has unexpected child %s\n", nodes->name,
5527 NULL);
5528 ret = -1;
5529 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005530 nodes = nodes->next;
5531 }
5532 return (ret);
5533}
5534
5535/**
5536 * xmlRelaxNGCheckReference:
5537 * @ref: the ref
5538 * @ctxt: a Relax-NG parser context
5539 * @name: the name associated to the defines
5540 *
5541 * Applies the 4.17. combine attribute rule for all the define
5542 * element of a given grammar using the same name.
5543 */
5544static void
5545xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
Daniel Veillard4c004142003-10-07 11:33:24 +00005546 xmlRelaxNGParserCtxtPtr ctxt,
5547 const xmlChar * name)
5548{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005549 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005550 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005551
5552 grammar = ctxt->grammar;
5553 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005554 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5555 "Internal error: no grammar in CheckReference %s\n",
5556 name, NULL);
5557 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005558 }
5559 if (ref->content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005560 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5561 "Internal error: reference has content in CheckReference %s\n",
5562 name, NULL);
5563 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005564 }
5565 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005566 def = xmlHashLookup(grammar->defs, name);
5567 if (def != NULL) {
5568 cur = ref;
5569 while (cur != NULL) {
5570 cur->content = def;
5571 cur = cur->nextHash;
5572 }
5573 } else {
5574 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5575 "Reference %s has no matching definition\n", name,
5576 NULL);
5577 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005578 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005579 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5580 "Reference %s has no matching definition\n", name,
5581 NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005582 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005583}
5584
5585/**
5586 * xmlRelaxNGCheckCombine:
5587 * @define: the define(s) list
5588 * @ctxt: a Relax-NG parser context
5589 * @name: the name associated to the defines
5590 *
5591 * Applies the 4.17. combine attribute rule for all the define
5592 * element of a given grammar using the same name.
5593 */
5594static void
5595xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
Daniel Veillard4c004142003-10-07 11:33:24 +00005596 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name)
5597{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005598 xmlChar *combine;
5599 int choiceOrInterleave = -1;
5600 int missing = 0;
5601 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5602
5603 if (define->nextHash == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005604 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005605 cur = define;
5606 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005607 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5608 if (combine != NULL) {
5609 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5610 if (choiceOrInterleave == -1)
5611 choiceOrInterleave = 1;
5612 else if (choiceOrInterleave == 0) {
5613 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5614 "Defines for %s use both 'choice' and 'interleave'\n",
5615 name, NULL);
5616 }
5617 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5618 if (choiceOrInterleave == -1)
5619 choiceOrInterleave = 0;
5620 else if (choiceOrInterleave == 1) {
5621 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5622 "Defines for %s use both 'choice' and 'interleave'\n",
5623 name, NULL);
5624 }
5625 } else {
5626 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
5627 "Defines for %s use unknown combine value '%s''\n",
5628 name, combine);
5629 }
5630 xmlFree(combine);
5631 } else {
5632 if (missing == 0)
5633 missing = 1;
5634 else {
5635 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
5636 "Some defines for %s needs the combine attribute\n",
5637 name, NULL);
5638 }
5639 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005640
Daniel Veillard4c004142003-10-07 11:33:24 +00005641 cur = cur->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005642 }
5643#ifdef DEBUG
5644 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005645 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5646 name, choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005647#endif
5648 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005649 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005650 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005651 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005652 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005653 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005654 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005655 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005656 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005657 tmp = define;
5658 last = NULL;
5659 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005660 if (tmp->content != NULL) {
5661 if (tmp->content->next != NULL) {
5662 /*
5663 * we need first to create a wrapper.
5664 */
5665 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5666 if (tmp2 == NULL)
5667 break;
5668 tmp2->type = XML_RELAXNG_GROUP;
5669 tmp2->content = tmp->content;
5670 } else {
5671 tmp2 = tmp->content;
5672 }
5673 if (last == NULL) {
5674 cur->content = tmp2;
5675 } else {
5676 last->next = tmp2;
5677 }
5678 last = tmp2;
5679 }
5680 tmp->content = cur;
5681 tmp = tmp->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005682 }
5683 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005684 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005685 if (ctxt->interleaves == NULL)
5686 ctxt->interleaves = xmlHashCreate(10);
5687 if (ctxt->interleaves == NULL) {
5688 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5689 "Failed to create interleaves hash table\n", NULL,
5690 NULL);
5691 } else {
5692 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005693
Daniel Veillard4c004142003-10-07 11:33:24 +00005694 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5695 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5696 0) {
5697 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5698 "Failed to add %s to hash table\n",
5699 (const xmlChar *) tmpname, NULL);
5700 }
5701 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005702 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005703}
5704
5705/**
5706 * xmlRelaxNGCombineStart:
5707 * @ctxt: a Relax-NG parser context
5708 * @grammar: the grammar
5709 *
5710 * Applies the 4.17. combine rule for all the start
5711 * element of a given grammar.
5712 */
5713static void
5714xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005715 xmlRelaxNGGrammarPtr grammar)
5716{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005717 xmlRelaxNGDefinePtr starts;
5718 xmlChar *combine;
5719 int choiceOrInterleave = -1;
5720 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005721 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005722
Daniel Veillard2df2de22003-02-17 23:34:33 +00005723 starts = grammar->start;
5724 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00005725 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005726 cur = starts;
5727 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005728 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5729 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5730 combine = NULL;
5731 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
5732 "Internal error: start element not found\n", NULL,
5733 NULL);
5734 } else {
5735 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5736 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005737
Daniel Veillard4c004142003-10-07 11:33:24 +00005738 if (combine != NULL) {
5739 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5740 if (choiceOrInterleave == -1)
5741 choiceOrInterleave = 1;
5742 else if (choiceOrInterleave == 0) {
5743 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5744 "<start> use both 'choice' and 'interleave'\n",
5745 NULL, NULL);
5746 }
5747 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5748 if (choiceOrInterleave == -1)
5749 choiceOrInterleave = 0;
5750 else if (choiceOrInterleave == 1) {
5751 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5752 "<start> use both 'choice' and 'interleave'\n",
5753 NULL, NULL);
5754 }
5755 } else {
5756 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
5757 "<start> uses unknown combine value '%s''\n",
5758 combine, NULL);
5759 }
5760 xmlFree(combine);
5761 } else {
5762 if (missing == 0)
5763 missing = 1;
5764 else {
5765 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
5766 "Some <start> element miss the combine attribute\n",
5767 NULL, NULL);
5768 }
5769 }
5770
5771 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005772 }
5773#ifdef DEBUG
5774 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005775 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5776 choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005777#endif
5778 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005779 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005780 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005781 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005782 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005783 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005784 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005785 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005786 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005787 cur->content = grammar->start;
5788 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005789 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005790 if (ctxt->interleaves == NULL)
5791 ctxt->interleaves = xmlHashCreate(10);
5792 if (ctxt->interleaves == NULL) {
5793 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5794 "Failed to create interleaves hash table\n", NULL,
5795 NULL);
5796 } else {
5797 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005798
Daniel Veillard4c004142003-10-07 11:33:24 +00005799 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5800 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5801 0) {
5802 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5803 "Failed to add %s to hash table\n",
5804 (const xmlChar *) tmpname, NULL);
5805 }
5806 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005807 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005808}
5809
5810/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005811 * xmlRelaxNGCheckCycles:
5812 * @ctxt: a Relax-NG parser context
5813 * @nodes: grammar children nodes
5814 * @depth: the counter
5815 *
5816 * Check for cycles.
5817 *
5818 * Returns 0 if check passed, and -1 in case of error
5819 */
5820static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005821xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5822 xmlRelaxNGDefinePtr cur, int depth)
5823{
Daniel Veillardd4310742003-02-18 21:12:46 +00005824 int ret = 0;
5825
5826 while ((ret == 0) && (cur != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005827 if ((cur->type == XML_RELAXNG_REF) ||
5828 (cur->type == XML_RELAXNG_PARENTREF)) {
5829 if (cur->depth == -1) {
5830 cur->depth = depth;
5831 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5832 cur->depth = -2;
5833 } else if (depth == cur->depth) {
5834 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
5835 "Detected a cycle in %s references\n",
5836 cur->name, NULL);
5837 return (-1);
5838 }
5839 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5840 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5841 } else {
5842 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5843 }
5844 cur = cur->next;
Daniel Veillardd4310742003-02-18 21:12:46 +00005845 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005846 return (ret);
Daniel Veillardd4310742003-02-18 21:12:46 +00005847}
5848
5849/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005850 * xmlRelaxNGTryUnlink:
5851 * @ctxt: a Relax-NG parser context
5852 * @cur: the definition to unlink
5853 * @parent: the parent definition
5854 * @prev: the previous sibling definition
5855 *
5856 * Try to unlink a definition. If not possble make it a NOOP
5857 *
5858 * Returns the new prev definition
5859 */
5860static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005861xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5862 xmlRelaxNGDefinePtr cur,
5863 xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
5864{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005865 if (prev != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005866 prev->next = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005867 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005868 if (parent != NULL) {
5869 if (parent->content == cur)
5870 parent->content = cur->next;
5871 else if (parent->attrs == cur)
5872 parent->attrs = cur->next;
5873 else if (parent->nameClass == cur)
5874 parent->nameClass = cur->next;
5875 } else {
5876 cur->type = XML_RELAXNG_NOOP;
5877 prev = cur;
5878 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005879 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005880 return (prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005881}
5882
5883/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005884 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005885 * @ctxt: a Relax-NG parser context
5886 * @nodes: grammar children nodes
5887 *
5888 * Check for simplification of empty and notAllowed
5889 */
5890static void
Daniel Veillard4c004142003-10-07 11:33:24 +00005891xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5892 xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
5893{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005894 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005895
Daniel Veillardfd573f12003-03-16 17:52:32 +00005896 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005897 if ((cur->type == XML_RELAXNG_REF) ||
5898 (cur->type == XML_RELAXNG_PARENTREF)) {
5899 if (cur->depth != -3) {
5900 cur->depth = -3;
5901 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5902 }
5903 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5904 cur->parent = parent;
5905 if ((parent != NULL) &&
5906 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5907 (parent->type == XML_RELAXNG_LIST) ||
5908 (parent->type == XML_RELAXNG_GROUP) ||
5909 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5910 (parent->type == XML_RELAXNG_ONEORMORE) ||
5911 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5912 parent->type = XML_RELAXNG_NOT_ALLOWED;
5913 break;
5914 }
5915 if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
5916 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5917 } else
5918 prev = cur;
5919 } else if (cur->type == XML_RELAXNG_EMPTY) {
5920 cur->parent = parent;
5921 if ((parent != NULL) &&
5922 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5923 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5924 parent->type = XML_RELAXNG_EMPTY;
5925 break;
5926 }
5927 if ((parent != NULL) &&
5928 ((parent->type == XML_RELAXNG_GROUP) ||
5929 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5930 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5931 } else
5932 prev = cur;
5933 } else {
5934 cur->parent = parent;
5935 if (cur->content != NULL)
5936 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5937 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
5938 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5939 if (cur->nameClass != NULL)
5940 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5941 /*
5942 * On Elements, try to move attribute only generating rules on
5943 * the attrs rules.
5944 */
5945 if (cur->type == XML_RELAXNG_ELEMENT) {
5946 int attronly;
5947 xmlRelaxNGDefinePtr tmp, pre;
Daniel Veillardce192eb2003-04-16 15:58:05 +00005948
Daniel Veillard4c004142003-10-07 11:33:24 +00005949 while (cur->content != NULL) {
5950 attronly =
5951 xmlRelaxNGGenerateAttributes(ctxt, cur->content);
5952 if (attronly == 1) {
5953 /*
5954 * migrate cur->content to attrs
5955 */
5956 tmp = cur->content;
5957 cur->content = tmp->next;
5958 tmp->next = cur->attrs;
5959 cur->attrs = tmp;
5960 } else {
5961 /*
5962 * cur->content can generate elements or text
5963 */
5964 break;
5965 }
5966 }
5967 pre = cur->content;
5968 while ((pre != NULL) && (pre->next != NULL)) {
5969 tmp = pre->next;
5970 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
5971 if (attronly == 1) {
5972 /*
5973 * migrate tmp to attrs
5974 */
5975 pre->next = tmp->next;
5976 tmp->next = cur->attrs;
5977 cur->attrs = tmp;
5978 } else {
5979 pre = tmp;
5980 }
5981 }
5982 }
5983 /*
5984 * This may result in a simplification
5985 */
5986 if ((cur->type == XML_RELAXNG_GROUP) ||
5987 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5988 if (cur->content == NULL)
5989 cur->type = XML_RELAXNG_EMPTY;
5990 else if (cur->content->next == NULL) {
5991 if ((parent == NULL) && (prev == NULL)) {
5992 cur->type = XML_RELAXNG_NOOP;
5993 } else if (prev == NULL) {
5994 parent->content = cur->content;
5995 cur->content->next = cur->next;
5996 cur = cur->content;
5997 } else {
5998 cur->content->next = cur->next;
5999 prev->next = cur->content;
6000 cur = cur->content;
6001 }
6002 }
6003 }
6004 /*
6005 * the current node may have been transformed back
6006 */
6007 if ((cur->type == XML_RELAXNG_EXCEPT) &&
6008 (cur->content != NULL) &&
6009 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
6010 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6011 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6012 if ((parent != NULL) &&
6013 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6014 (parent->type == XML_RELAXNG_LIST) ||
6015 (parent->type == XML_RELAXNG_GROUP) ||
6016 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6017 (parent->type == XML_RELAXNG_ONEORMORE) ||
6018 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6019 parent->type = XML_RELAXNG_NOT_ALLOWED;
6020 break;
6021 }
6022 if ((parent != NULL) &&
6023 (parent->type == XML_RELAXNG_CHOICE)) {
6024 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6025 } else
6026 prev = cur;
6027 } else if (cur->type == XML_RELAXNG_EMPTY) {
6028 if ((parent != NULL) &&
6029 ((parent->type == XML_RELAXNG_ONEORMORE) ||
6030 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6031 parent->type = XML_RELAXNG_EMPTY;
6032 break;
6033 }
6034 if ((parent != NULL) &&
6035 ((parent->type == XML_RELAXNG_GROUP) ||
6036 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6037 (parent->type == XML_RELAXNG_CHOICE))) {
6038 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6039 } else
6040 prev = cur;
6041 } else {
6042 prev = cur;
6043 }
6044 }
6045 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006046 }
6047}
6048
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006049/**
6050 * xmlRelaxNGGroupContentType:
6051 * @ct1: the first content type
6052 * @ct2: the second content type
6053 *
6054 * Try to group 2 content types
6055 *
6056 * Returns the content type
6057 */
6058static xmlRelaxNGContentType
6059xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006060 xmlRelaxNGContentType ct2)
6061{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006062 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006063 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6064 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006065 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006066 return (ct2);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006067 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006068 return (ct1);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006069 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00006070 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6071 return (XML_RELAXNG_CONTENT_COMPLEX);
6072 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006073}
6074
6075/**
6076 * xmlRelaxNGMaxContentType:
6077 * @ct1: the first content type
6078 * @ct2: the second content type
6079 *
6080 * Compute the max content-type
6081 *
6082 * Returns the content type
6083 */
6084static xmlRelaxNGContentType
6085xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006086 xmlRelaxNGContentType ct2)
6087{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006088 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006089 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6090 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006091 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006092 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6093 return (XML_RELAXNG_CONTENT_SIMPLE);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006094 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006095 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6096 return (XML_RELAXNG_CONTENT_COMPLEX);
6097 return (XML_RELAXNG_CONTENT_EMPTY);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006098}
Daniel Veillard77648bb2003-02-20 15:03:22 +00006099
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006100/**
6101 * xmlRelaxNGCheckRules:
6102 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006103 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00006104 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00006105 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006106 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006107 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006108 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006109 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006110 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006111static xmlRelaxNGContentType
Daniel Veillard4c004142003-10-07 11:33:24 +00006112xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6113 xmlRelaxNGDefinePtr cur, int flags,
6114 xmlRelaxNGType ptype)
6115{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006116 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006117 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006118
Daniel Veillardfd573f12003-03-16 17:52:32 +00006119 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006120 ret = XML_RELAXNG_CONTENT_EMPTY;
6121 if ((cur->type == XML_RELAXNG_REF) ||
6122 (cur->type == XML_RELAXNG_PARENTREF)) {
6123 if (flags & XML_RELAXNG_IN_LIST) {
6124 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6125 "Found forbidden pattern list//ref\n", NULL,
6126 NULL);
6127 }
6128 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6129 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6130 "Found forbidden pattern data/except//ref\n",
6131 NULL, NULL);
6132 }
6133 if (cur->depth > -4) {
6134 cur->depth = -4;
6135 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6136 flags, cur->type);
6137 cur->depth = ret - 15;
6138 } else if (cur->depth == -4) {
6139 ret = XML_RELAXNG_CONTENT_COMPLEX;
6140 } else {
6141 ret = (xmlRelaxNGContentType) (cur->depth + 15);
6142 }
6143 } else if (cur->type == XML_RELAXNG_ELEMENT) {
6144 /*
6145 * The 7.3 Attribute derivation rule for groups is plugged there
6146 */
6147 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6148 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6149 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6150 "Found forbidden pattern data/except//element(ref)\n",
6151 NULL, NULL);
6152 }
6153 if (flags & XML_RELAXNG_IN_LIST) {
6154 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6155 "Found forbidden pattern list//element(ref)\n",
6156 NULL, NULL);
6157 }
6158 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6159 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6160 "Found forbidden pattern attribute//element(ref)\n",
6161 NULL, NULL);
6162 }
6163 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6164 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6165 "Found forbidden pattern attribute//element(ref)\n",
6166 NULL, NULL);
6167 }
6168 /*
6169 * reset since in the simple form elements are only child
6170 * of grammar/define
6171 */
6172 nflags = 0;
6173 ret =
6174 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6175 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6176 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6177 "Element %s attributes have a content type error\n",
6178 cur->name, NULL);
6179 }
6180 ret =
6181 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6182 cur->type);
6183 if (ret == XML_RELAXNG_CONTENT_ERROR) {
6184 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6185 "Element %s has a content type error\n",
6186 cur->name, NULL);
6187 } else {
6188 ret = XML_RELAXNG_CONTENT_COMPLEX;
6189 }
6190 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6191 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6192 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6193 "Found forbidden pattern attribute//attribute\n",
6194 NULL, NULL);
6195 }
6196 if (flags & XML_RELAXNG_IN_LIST) {
6197 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6198 "Found forbidden pattern list//attribute\n",
6199 NULL, NULL);
6200 }
6201 if (flags & XML_RELAXNG_IN_OOMGROUP) {
6202 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6203 "Found forbidden pattern oneOrMore//group//attribute\n",
6204 NULL, NULL);
6205 }
6206 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6207 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6208 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6209 NULL, NULL);
6210 }
6211 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6212 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6213 "Found forbidden pattern data/except//attribute\n",
6214 NULL, NULL);
6215 }
6216 if (flags & XML_RELAXNG_IN_START) {
6217 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6218 "Found forbidden pattern start//attribute\n",
6219 NULL, NULL);
6220 }
6221 if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6222 && (cur->name == NULL)) {
6223 if (cur->ns == NULL) {
6224 xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6225 "Found anyName attribute without oneOrMore ancestor\n",
6226 NULL, NULL);
6227 } else {
6228 xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6229 "Found nsName attribute without oneOrMore ancestor\n",
6230 NULL, NULL);
6231 }
6232 }
6233 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6234 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6235 ret = XML_RELAXNG_CONTENT_EMPTY;
6236 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6237 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6238 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6239 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6240 "Found forbidden pattern data/except//oneOrMore\n",
6241 NULL, NULL);
6242 }
6243 if (flags & XML_RELAXNG_IN_START) {
6244 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6245 "Found forbidden pattern start//oneOrMore\n",
6246 NULL, NULL);
6247 }
6248 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6249 ret =
6250 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6251 cur->type);
6252 ret = xmlRelaxNGGroupContentType(ret, ret);
6253 } else if (cur->type == XML_RELAXNG_LIST) {
6254 if (flags & XML_RELAXNG_IN_LIST) {
6255 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6256 "Found forbidden pattern list//list\n", NULL,
6257 NULL);
6258 }
6259 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6260 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6261 "Found forbidden pattern data/except//list\n",
6262 NULL, NULL);
6263 }
6264 if (flags & XML_RELAXNG_IN_START) {
6265 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6266 "Found forbidden pattern start//list\n", NULL,
6267 NULL);
6268 }
6269 nflags = flags | XML_RELAXNG_IN_LIST;
6270 ret =
6271 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6272 cur->type);
6273 } else if (cur->type == XML_RELAXNG_GROUP) {
6274 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6275 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6276 "Found forbidden pattern data/except//group\n",
6277 NULL, NULL);
6278 }
6279 if (flags & XML_RELAXNG_IN_START) {
6280 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6281 "Found forbidden pattern start//group\n", NULL,
6282 NULL);
6283 }
6284 if (flags & XML_RELAXNG_IN_ONEORMORE)
6285 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6286 else
6287 nflags = flags;
6288 ret =
6289 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6290 cur->type);
6291 /*
6292 * The 7.3 Attribute derivation rule for groups is plugged there
6293 */
6294 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6295 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6296 if (flags & XML_RELAXNG_IN_LIST) {
6297 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6298 "Found forbidden pattern list//interleave\n",
6299 NULL, NULL);
6300 }
6301 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6302 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6303 "Found forbidden pattern data/except//interleave\n",
6304 NULL, NULL);
6305 }
6306 if (flags & XML_RELAXNG_IN_START) {
6307 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6308 "Found forbidden pattern start//interleave\n",
6309 NULL, NULL);
6310 }
6311 if (flags & XML_RELAXNG_IN_ONEORMORE)
6312 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6313 else
6314 nflags = flags;
6315 ret =
6316 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6317 cur->type);
6318 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6319 if ((cur->parent != NULL) &&
6320 (cur->parent->type == XML_RELAXNG_DATATYPE))
6321 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6322 else
6323 nflags = flags;
6324 ret =
6325 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6326 cur->type);
6327 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6328 if (flags & XML_RELAXNG_IN_START) {
6329 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6330 "Found forbidden pattern start//data\n", NULL,
6331 NULL);
6332 }
6333 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6334 ret = XML_RELAXNG_CONTENT_SIMPLE;
6335 } else if (cur->type == XML_RELAXNG_VALUE) {
6336 if (flags & XML_RELAXNG_IN_START) {
6337 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6338 "Found forbidden pattern start//value\n", NULL,
6339 NULL);
6340 }
6341 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6342 ret = XML_RELAXNG_CONTENT_SIMPLE;
6343 } else if (cur->type == XML_RELAXNG_TEXT) {
6344 if (flags & XML_RELAXNG_IN_LIST) {
6345 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6346 "Found forbidden pattern list//text\n", NULL,
6347 NULL);
6348 }
6349 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6350 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6351 "Found forbidden pattern data/except//text\n",
6352 NULL, NULL);
6353 }
6354 if (flags & XML_RELAXNG_IN_START) {
6355 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6356 "Found forbidden pattern start//text\n", NULL,
6357 NULL);
6358 }
6359 ret = XML_RELAXNG_CONTENT_COMPLEX;
6360 } else if (cur->type == XML_RELAXNG_EMPTY) {
6361 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6362 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6363 "Found forbidden pattern data/except//empty\n",
6364 NULL, NULL);
6365 }
6366 if (flags & XML_RELAXNG_IN_START) {
6367 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6368 "Found forbidden pattern start//empty\n", NULL,
6369 NULL);
6370 }
6371 ret = XML_RELAXNG_CONTENT_EMPTY;
6372 } else if (cur->type == XML_RELAXNG_CHOICE) {
6373 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6374 ret =
6375 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6376 } else {
6377 ret =
6378 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6379 }
6380 cur = cur->next;
6381 if (ptype == XML_RELAXNG_GROUP) {
6382 val = xmlRelaxNGGroupContentType(val, ret);
6383 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6384 tmp = xmlRelaxNGGroupContentType(val, ret);
6385 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6386 tmp = xmlRelaxNGMaxContentType(val, ret);
6387 } else if (ptype == XML_RELAXNG_CHOICE) {
6388 val = xmlRelaxNGMaxContentType(val, ret);
6389 } else if (ptype == XML_RELAXNG_LIST) {
6390 val = XML_RELAXNG_CONTENT_SIMPLE;
6391 } else if (ptype == XML_RELAXNG_EXCEPT) {
6392 if (ret == XML_RELAXNG_CONTENT_ERROR)
6393 val = XML_RELAXNG_CONTENT_ERROR;
6394 else
6395 val = XML_RELAXNG_CONTENT_SIMPLE;
6396 } else {
6397 val = xmlRelaxNGGroupContentType(val, ret);
6398 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006399
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006400 }
Daniel Veillard4c004142003-10-07 11:33:24 +00006401 return (val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006402}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006403
6404/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006405 * xmlRelaxNGParseGrammar:
6406 * @ctxt: a Relax-NG parser context
6407 * @nodes: grammar children nodes
6408 *
6409 * parse a Relax-NG <grammar> node
6410 *
6411 * Returns the internal xmlRelaxNGGrammarPtr built or
6412 * NULL in case of error
6413 */
6414static xmlRelaxNGGrammarPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006415xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6416{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006417 xmlRelaxNGGrammarPtr ret, tmp, old;
6418
Daniel Veillardc482e262003-02-26 14:48:48 +00006419#ifdef DEBUG_GRAMMAR
6420 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6421#endif
6422
Daniel Veillard6eadf632003-01-23 18:29:16 +00006423 ret = xmlRelaxNGNewGrammar(ctxt);
6424 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006425 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006426
6427 /*
6428 * Link the new grammar in the tree
6429 */
6430 ret->parent = ctxt->grammar;
6431 if (ctxt->grammar != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006432 tmp = ctxt->grammar->children;
6433 if (tmp == NULL) {
6434 ctxt->grammar->children = ret;
6435 } else {
6436 while (tmp->next != NULL)
6437 tmp = tmp->next;
6438 tmp->next = ret;
6439 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006440 }
6441
6442 old = ctxt->grammar;
6443 ctxt->grammar = ret;
6444 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6445 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006446 if (ctxt->grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006447 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6448 "Failed to parse <grammar> content\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006449 } else if (ctxt->grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006450 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6451 "Element <grammar> has no <start>\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006452 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006453
6454 /*
6455 * Apply 4.17 mergingd rules to defines and starts
6456 */
6457 xmlRelaxNGCombineStart(ctxt, ret);
6458 if (ret->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006459 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6460 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006461 }
6462
6463 /*
6464 * link together defines and refs in this grammar
6465 */
6466 if (ret->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006467 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6468 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006469 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006470
Daniel Veillard6eadf632003-01-23 18:29:16 +00006471 ctxt->grammar = old;
Daniel Veillard4c004142003-10-07 11:33:24 +00006472 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006473}
6474
6475/**
6476 * xmlRelaxNGParseDocument:
6477 * @ctxt: a Relax-NG parser context
6478 * @node: the root node of the RelaxNG schema
6479 *
6480 * parse a Relax-NG definition resource and build an internal
6481 * xmlRelaxNG struture which can be used to validate instances.
6482 *
6483 * Returns the internal XML RelaxNG structure built or
6484 * NULL in case of error
6485 */
6486static xmlRelaxNGPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006487xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6488{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006489 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006490 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006491 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006492
6493 if ((ctxt == NULL) || (node == NULL))
6494 return (NULL);
6495
6496 schema = xmlRelaxNGNewRelaxNG(ctxt);
6497 if (schema == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006498 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006499
Daniel Veillard276be4a2003-01-24 01:03:34 +00006500 olddefine = ctxt->define;
6501 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006502 if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006503 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006504 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006505 xmlRelaxNGGrammarPtr tmp, ret;
Daniel Veillardc482e262003-02-26 14:48:48 +00006506
Daniel Veillard4c004142003-10-07 11:33:24 +00006507 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6508 if (schema->topgrammar == NULL) {
6509 return (schema);
6510 }
6511 /*
6512 * Link the new grammar in the tree
6513 */
6514 ret->parent = ctxt->grammar;
6515 if (ctxt->grammar != NULL) {
6516 tmp = ctxt->grammar->children;
6517 if (tmp == NULL) {
6518 ctxt->grammar->children = ret;
6519 } else {
6520 while (tmp->next != NULL)
6521 tmp = tmp->next;
6522 tmp->next = ret;
6523 }
6524 }
6525 old = ctxt->grammar;
6526 ctxt->grammar = ret;
6527 xmlRelaxNGParseStart(ctxt, node);
6528 if (old != NULL)
6529 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006530 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006531 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006532 if (schema->topgrammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006533 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6534 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6535 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6536 while ((schema->topgrammar->start != NULL) &&
6537 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6538 (schema->topgrammar->start->next != NULL))
6539 schema->topgrammar->start =
6540 schema->topgrammar->start->content;
6541 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6542 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6543 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006544 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006545#ifdef DEBUG
6546 if (schema == NULL)
6547 xmlGenericError(xmlGenericErrorContext,
6548 "xmlRelaxNGParseDocument() failed\n");
6549#endif
6550
6551 return (schema);
6552}
6553
6554/************************************************************************
6555 * *
6556 * Reading RelaxNGs *
6557 * *
6558 ************************************************************************/
6559
6560/**
6561 * xmlRelaxNGNewParserCtxt:
6562 * @URL: the location of the schema
6563 *
6564 * Create an XML RelaxNGs parse context for that file/resource expected
6565 * to contain an XML RelaxNGs file.
6566 *
6567 * Returns the parser context or NULL in case of error
6568 */
6569xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006570xmlRelaxNGNewParserCtxt(const char *URL)
6571{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006572 xmlRelaxNGParserCtxtPtr ret;
6573
6574 if (URL == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006575 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006576
Daniel Veillard4c004142003-10-07 11:33:24 +00006577 ret =
6578 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006579 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006580 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006581 return (NULL);
6582 }
6583 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard4c004142003-10-07 11:33:24 +00006584 ret->URL = xmlStrdup((const xmlChar *) URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006585 ret->error = xmlGenericError;
6586 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006587 return (ret);
6588}
6589
6590/**
6591 * xmlRelaxNGNewMemParserCtxt:
6592 * @buffer: a pointer to a char array containing the schemas
6593 * @size: the size of the array
6594 *
6595 * Create an XML RelaxNGs parse context for that memory buffer expected
6596 * to contain an XML RelaxNGs file.
6597 *
6598 * Returns the parser context or NULL in case of error
6599 */
6600xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006601xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6602{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006603 xmlRelaxNGParserCtxtPtr ret;
6604
6605 if ((buffer == NULL) || (size <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00006606 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006607
Daniel Veillard4c004142003-10-07 11:33:24 +00006608 ret =
6609 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006610 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006611 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006612 return (NULL);
6613 }
6614 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6615 ret->buffer = buffer;
6616 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006617 ret->error = xmlGenericError;
6618 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006619 return (ret);
6620}
6621
6622/**
Daniel Veillard33300b42003-04-17 09:09:19 +00006623 * xmlRelaxNGNewDocParserCtxt:
6624 * @doc: a preparsed document tree
6625 *
6626 * Create an XML RelaxNGs parser context for that document.
6627 * Note: since the process of compiling a RelaxNG schemas modifies the
6628 * document, the @doc parameter is duplicated internally.
6629 *
6630 * Returns the parser context or NULL in case of error
6631 */
6632xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006633xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6634{
Daniel Veillard33300b42003-04-17 09:09:19 +00006635 xmlRelaxNGParserCtxtPtr ret;
6636 xmlDocPtr copy;
6637
6638 if (doc == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006639 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006640 copy = xmlCopyDoc(doc, 1);
6641 if (copy == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006642 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006643
Daniel Veillard4c004142003-10-07 11:33:24 +00006644 ret =
6645 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard33300b42003-04-17 09:09:19 +00006646 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006647 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard33300b42003-04-17 09:09:19 +00006648 return (NULL);
6649 }
6650 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6651 ret->document = copy;
6652 ret->userData = xmlGenericErrorContext;
6653 return (ret);
6654}
6655
6656/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006657 * xmlRelaxNGFreeParserCtxt:
6658 * @ctxt: the schema parser context
6659 *
6660 * Free the resources associated to the schema parser context
6661 */
6662void
Daniel Veillard4c004142003-10-07 11:33:24 +00006663xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6664{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006665 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006666 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006667 if (ctxt->URL != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006668 xmlFree(ctxt->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006669 if (ctxt->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006670 xmlRelaxNGFreeDocument(ctxt->doc);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006671 if (ctxt->interleaves != NULL)
6672 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006673 if (ctxt->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006674 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006675 if (ctxt->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006676 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006677 if (ctxt->docTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006678 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006679 if (ctxt->incTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006680 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006681 if (ctxt->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006682 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +00006683
Daniel Veillard4c004142003-10-07 11:33:24 +00006684 for (i = 0; i < ctxt->defNr; i++)
6685 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6686 xmlFree(ctxt->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006687 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006688 xmlFree(ctxt);
6689}
6690
Daniel Veillard6eadf632003-01-23 18:29:16 +00006691/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006692 * xmlRelaxNGNormExtSpace:
6693 * @value: a value
6694 *
6695 * Removes the leading and ending spaces of the value
6696 * The string is modified "in situ"
6697 */
6698static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006699xmlRelaxNGNormExtSpace(xmlChar * value)
6700{
Daniel Veillardd2298792003-02-14 16:54:11 +00006701 xmlChar *start = value;
6702 xmlChar *cur = value;
Daniel Veillardd2298792003-02-14 16:54:11 +00006703
Daniel Veillard4c004142003-10-07 11:33:24 +00006704 if (value == NULL)
6705 return;
6706
William M. Brack76e95df2003-10-18 16:20:14 +00006707 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006708 cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +00006709 if (cur == start) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006710 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006711 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006712 cur++;
6713 if (*cur == 0)
6714 return;
6715 start = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006716 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006717 cur++;
6718 if (*cur == 0) {
6719 *start = 0;
6720 return;
6721 }
6722 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006723 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006724 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006725 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006726 *start++ = *cur++;
6727 if (*cur == 0) {
6728 *start = 0;
6729 return;
6730 }
6731 /* don't try to normalize the inner spaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006732 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006733 cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006734 if (*cur == 0) {
6735 *start = 0;
6736 return;
6737 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00006738 *start++ = *cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006739 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006740 }
6741}
6742
6743/**
6744 * xmlRelaxNGCheckAttributes:
6745 * @ctxt: a Relax-NG parser context
6746 * @node: a Relax-NG node
6747 *
6748 * Check all the attributes on the given node
6749 */
6750static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006751xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6752{
Daniel Veillardd2298792003-02-14 16:54:11 +00006753 xmlAttrPtr cur, next;
6754
6755 cur = node->properties;
6756 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006757 next = cur->next;
6758 if ((cur->ns == NULL) ||
6759 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6760 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6761 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6762 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6763 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6764 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6765 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6766 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6767 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6768 "Attribute %s is not allowed on %s\n",
6769 cur->name, node->name);
6770 }
6771 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6772 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6773 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6774 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6775 "Attribute %s is not allowed on %s\n",
6776 cur->name, node->name);
6777 }
6778 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6779 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6780 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6781 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6782 "Attribute %s is not allowed on %s\n",
6783 cur->name, node->name);
6784 }
6785 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6786 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6787 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6788 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6789 "Attribute %s is not allowed on %s\n",
6790 cur->name, node->name);
6791 }
6792 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6793 xmlChar *val;
6794 xmlURIPtr uri;
Daniel Veillardd2298792003-02-14 16:54:11 +00006795
Daniel Veillard4c004142003-10-07 11:33:24 +00006796 val = xmlNodeListGetString(node->doc, cur->children, 1);
6797 if (val != NULL) {
6798 if (val[0] != 0) {
6799 uri = xmlParseURI((const char *) val);
6800 if (uri == NULL) {
6801 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
6802 "Attribute %s contains invalid URI %s\n",
6803 cur->name, val);
6804 } else {
6805 if (uri->scheme == NULL) {
6806 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
6807 "Attribute %s URI %s is not absolute\n",
6808 cur->name, val);
6809 }
6810 if (uri->fragment != NULL) {
6811 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
6812 "Attribute %s URI %s has a fragment ID\n",
6813 cur->name, val);
6814 }
6815 xmlFreeURI(uri);
6816 }
6817 }
6818 xmlFree(val);
6819 }
6820 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6821 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
6822 "Unknown attribute %s on %s\n", cur->name,
6823 node->name);
6824 }
6825 }
6826 cur = next;
Daniel Veillardd2298792003-02-14 16:54:11 +00006827 }
6828}
6829
6830/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006831 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006832 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006833 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006834 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006835 * Cleanup the subtree from unwanted nodes for parsing, resolve
6836 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006837 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006838static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006839xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
6840{
Daniel Veillardc5312d72003-02-21 17:14:10 +00006841 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006842
Daniel Veillard6eadf632003-01-23 18:29:16 +00006843 delete = NULL;
6844 cur = root;
6845 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006846 if (delete != NULL) {
6847 xmlUnlinkNode(delete);
6848 xmlFreeNode(delete);
6849 delete = NULL;
6850 }
6851 if (cur->type == XML_ELEMENT_NODE) {
6852 /*
6853 * Simplification 4.1. Annotations
6854 */
6855 if ((cur->ns == NULL) ||
6856 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6857 if ((cur->parent != NULL) &&
6858 (cur->parent->type == XML_ELEMENT_NODE) &&
6859 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6860 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6861 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6862 xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
6863 "element %s doesn't allow foreign elements\n",
6864 cur->parent->name, NULL);
6865 }
6866 delete = cur;
6867 goto skip_children;
6868 } else {
6869 xmlRelaxNGCleanupAttributes(ctxt, cur);
6870 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6871 xmlChar *href, *ns, *base, *URL;
6872 xmlRelaxNGDocumentPtr docu;
6873 xmlNodePtr tmp;
Daniel Veillard6dc91962004-03-22 19:10:02 +00006874 xmlURIPtr uri;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006875
Daniel Veillard4c004142003-10-07 11:33:24 +00006876 ns = xmlGetProp(cur, BAD_CAST "ns");
6877 if (ns == NULL) {
6878 tmp = cur->parent;
6879 while ((tmp != NULL) &&
6880 (tmp->type == XML_ELEMENT_NODE)) {
6881 ns = xmlGetProp(tmp, BAD_CAST "ns");
6882 if (ns != NULL)
6883 break;
6884 tmp = tmp->parent;
6885 }
6886 }
6887 href = xmlGetProp(cur, BAD_CAST "href");
6888 if (href == NULL) {
6889 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6890 "xmlRelaxNGParse: externalRef has no href attribute\n",
6891 NULL, NULL);
6892 delete = cur;
6893 goto skip_children;
6894 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00006895 uri = xmlParseURI((const char *) href);
6896 if (uri == NULL) {
6897 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6898 "Incorrect URI for externalRef %s\n",
6899 href, NULL);
6900 if (href != NULL)
6901 xmlFree(href);
6902 delete = cur;
6903 goto skip_children;
6904 }
6905 if (uri->fragment != NULL) {
6906 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6907 "Fragment forbidden in URI for externalRef %s\n",
6908 href, NULL);
6909 xmlFreeURI(uri);
6910 if (href != NULL)
6911 xmlFree(href);
6912 delete = cur;
6913 goto skip_children;
6914 }
6915 xmlFreeURI(uri);
Daniel Veillard4c004142003-10-07 11:33:24 +00006916 base = xmlNodeGetBase(cur->doc, cur);
6917 URL = xmlBuildURI(href, base);
6918 if (URL == NULL) {
6919 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6920 "Failed to compute URL for externalRef %s\n",
6921 href, NULL);
6922 if (href != NULL)
6923 xmlFree(href);
6924 if (base != NULL)
6925 xmlFree(base);
6926 delete = cur;
6927 goto skip_children;
6928 }
6929 if (href != NULL)
6930 xmlFree(href);
6931 if (base != NULL)
6932 xmlFree(base);
6933 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6934 if (docu == NULL) {
6935 xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
6936 "Failed to load externalRef %s\n", URL,
6937 NULL);
6938 xmlFree(URL);
6939 delete = cur;
6940 goto skip_children;
6941 }
6942 if (ns != NULL)
6943 xmlFree(ns);
6944 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00006945 cur->psvi = docu;
Daniel Veillard4c004142003-10-07 11:33:24 +00006946 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6947 xmlChar *href, *ns, *base, *URL;
6948 xmlRelaxNGIncludePtr incl;
6949 xmlNodePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006950
Daniel Veillard4c004142003-10-07 11:33:24 +00006951 href = xmlGetProp(cur, BAD_CAST "href");
6952 if (href == NULL) {
6953 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6954 "xmlRelaxNGParse: include has no href attribute\n",
6955 NULL, NULL);
6956 delete = cur;
6957 goto skip_children;
6958 }
6959 base = xmlNodeGetBase(cur->doc, cur);
6960 URL = xmlBuildURI(href, base);
6961 if (URL == NULL) {
6962 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6963 "Failed to compute URL for include %s\n",
6964 href, NULL);
6965 if (href != NULL)
6966 xmlFree(href);
6967 if (base != NULL)
6968 xmlFree(base);
6969 delete = cur;
6970 goto skip_children;
6971 }
6972 if (href != NULL)
6973 xmlFree(href);
6974 if (base != NULL)
6975 xmlFree(base);
6976 ns = xmlGetProp(cur, BAD_CAST "ns");
6977 if (ns == NULL) {
6978 tmp = cur->parent;
6979 while ((tmp != NULL) &&
6980 (tmp->type == XML_ELEMENT_NODE)) {
6981 ns = xmlGetProp(tmp, BAD_CAST "ns");
6982 if (ns != NULL)
6983 break;
6984 tmp = tmp->parent;
6985 }
6986 }
6987 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6988 if (ns != NULL)
6989 xmlFree(ns);
6990 if (incl == NULL) {
6991 xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
6992 "Failed to load include %s\n", URL,
6993 NULL);
6994 xmlFree(URL);
6995 delete = cur;
6996 goto skip_children;
6997 }
6998 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00006999 cur->psvi = incl;
Daniel Veillard4c004142003-10-07 11:33:24 +00007000 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7001 (xmlStrEqual(cur->name, BAD_CAST "attribute")))
7002 {
7003 xmlChar *name, *ns;
7004 xmlNodePtr text = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007005
Daniel Veillard4c004142003-10-07 11:33:24 +00007006 /*
7007 * Simplification 4.8. name attribute of element
7008 * and attribute elements
7009 */
7010 name = xmlGetProp(cur, BAD_CAST "name");
7011 if (name != NULL) {
7012 if (cur->children == NULL) {
7013 text =
7014 xmlNewChild(cur, cur->ns, BAD_CAST "name",
7015 name);
7016 } else {
7017 xmlNodePtr node;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007018
Daniel Veillard4c004142003-10-07 11:33:24 +00007019 node = xmlNewNode(cur->ns, BAD_CAST "name");
7020 if (node != NULL) {
7021 xmlAddPrevSibling(cur->children, node);
7022 text = xmlNewText(name);
7023 xmlAddChild(node, text);
7024 text = node;
7025 }
7026 }
7027 if (text == NULL) {
7028 xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7029 "Failed to create a name %s element\n",
7030 name, NULL);
7031 }
7032 xmlUnsetProp(cur, BAD_CAST "name");
7033 xmlFree(name);
7034 ns = xmlGetProp(cur, BAD_CAST "ns");
7035 if (ns != NULL) {
7036 if (text != NULL) {
7037 xmlSetProp(text, BAD_CAST "ns", ns);
7038 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7039 }
7040 xmlFree(ns);
7041 } else if (xmlStrEqual(cur->name,
7042 BAD_CAST "attribute")) {
7043 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7044 }
7045 }
7046 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7047 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7048 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7049 /*
7050 * Simplification 4.8. name attribute of element
7051 * and attribute elements
7052 */
7053 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7054 xmlNodePtr node;
7055 xmlChar *ns = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007056
Daniel Veillard4c004142003-10-07 11:33:24 +00007057 node = cur->parent;
7058 while ((node != NULL) &&
7059 (node->type == XML_ELEMENT_NODE)) {
7060 ns = xmlGetProp(node, BAD_CAST "ns");
7061 if (ns != NULL) {
7062 break;
7063 }
7064 node = node->parent;
7065 }
7066 if (ns == NULL) {
7067 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7068 } else {
7069 xmlSetProp(cur, BAD_CAST "ns", ns);
7070 xmlFree(ns);
7071 }
7072 }
7073 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7074 xmlChar *name, *local, *prefix;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007075
Daniel Veillard4c004142003-10-07 11:33:24 +00007076 /*
7077 * Simplification: 4.10. QNames
7078 */
7079 name = xmlNodeGetContent(cur);
7080 if (name != NULL) {
7081 local = xmlSplitQName2(name, &prefix);
7082 if (local != NULL) {
7083 xmlNsPtr ns;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007084
Daniel Veillard4c004142003-10-07 11:33:24 +00007085 ns = xmlSearchNs(cur->doc, cur, prefix);
7086 if (ns == NULL) {
7087 xmlRngPErr(ctxt, cur,
7088 XML_RNGP_PREFIX_UNDEFINED,
7089 "xmlRelaxNGParse: no namespace for prefix %s\n",
7090 prefix, NULL);
7091 } else {
7092 xmlSetProp(cur, BAD_CAST "ns",
7093 ns->href);
7094 xmlNodeSetContent(cur, local);
7095 }
7096 xmlFree(local);
7097 xmlFree(prefix);
7098 }
7099 xmlFree(name);
7100 }
7101 }
7102 /*
7103 * 4.16
7104 */
7105 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7106 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7107 xmlRngPErr(ctxt, cur,
7108 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7109 "Found nsName/except//nsName forbidden construct\n",
7110 NULL, NULL);
7111 }
7112 }
7113 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7114 (cur != root)) {
7115 int oldflags = ctxt->flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007116
Daniel Veillard4c004142003-10-07 11:33:24 +00007117 /*
7118 * 4.16
7119 */
7120 if ((cur->parent != NULL) &&
7121 (xmlStrEqual
7122 (cur->parent->name, BAD_CAST "anyName"))) {
7123 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7124 xmlRelaxNGCleanupTree(ctxt, cur);
7125 ctxt->flags = oldflags;
7126 goto skip_children;
7127 } else if ((cur->parent != NULL) &&
7128 (xmlStrEqual
7129 (cur->parent->name, BAD_CAST "nsName"))) {
7130 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7131 xmlRelaxNGCleanupTree(ctxt, cur);
7132 ctxt->flags = oldflags;
7133 goto skip_children;
7134 }
7135 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7136 /*
7137 * 4.16
7138 */
7139 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7140 xmlRngPErr(ctxt, cur,
7141 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7142 "Found anyName/except//anyName forbidden construct\n",
7143 NULL, NULL);
7144 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7145 xmlRngPErr(ctxt, cur,
7146 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7147 "Found nsName/except//anyName forbidden construct\n",
7148 NULL, NULL);
7149 }
7150 }
7151 /*
7152 * Thisd is not an else since "include" is transformed
7153 * into a div
7154 */
7155 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7156 xmlChar *ns;
7157 xmlNodePtr child, ins, tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007158
Daniel Veillard4c004142003-10-07 11:33:24 +00007159 /*
7160 * implements rule 4.11
7161 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00007162
Daniel Veillard4c004142003-10-07 11:33:24 +00007163 ns = xmlGetProp(cur, BAD_CAST "ns");
7164
7165 child = cur->children;
7166 ins = cur;
7167 while (child != NULL) {
7168 if (ns != NULL) {
7169 if (!xmlHasProp(child, BAD_CAST "ns")) {
7170 xmlSetProp(child, BAD_CAST "ns", ns);
7171 }
7172 }
7173 tmp = child->next;
7174 xmlUnlinkNode(child);
7175 ins = xmlAddNextSibling(ins, child);
7176 child = tmp;
7177 }
7178 if (ns != NULL)
7179 xmlFree(ns);
7180 delete = cur;
7181 goto skip_children;
7182 }
7183 }
7184 }
7185 /*
7186 * Simplification 4.2 whitespaces
7187 */
7188 else if ((cur->type == XML_TEXT_NODE) ||
7189 (cur->type == XML_CDATA_SECTION_NODE)) {
7190 if (IS_BLANK_NODE(cur)) {
7191 if (cur->parent->type == XML_ELEMENT_NODE) {
7192 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7193 &&
7194 (!xmlStrEqual
7195 (cur->parent->name, BAD_CAST "param")))
7196 delete = cur;
7197 } else {
7198 delete = cur;
7199 goto skip_children;
7200 }
7201 }
7202 } else {
7203 delete = cur;
7204 goto skip_children;
7205 }
7206
7207 /*
7208 * Skip to next node
7209 */
7210 if (cur->children != NULL) {
7211 if ((cur->children->type != XML_ENTITY_DECL) &&
7212 (cur->children->type != XML_ENTITY_REF_NODE) &&
7213 (cur->children->type != XML_ENTITY_NODE)) {
7214 cur = cur->children;
7215 continue;
7216 }
7217 }
7218 skip_children:
7219 if (cur->next != NULL) {
7220 cur = cur->next;
7221 continue;
7222 }
7223
7224 do {
7225 cur = cur->parent;
7226 if (cur == NULL)
7227 break;
7228 if (cur == root) {
7229 cur = NULL;
7230 break;
7231 }
7232 if (cur->next != NULL) {
7233 cur = cur->next;
7234 break;
7235 }
7236 } while (cur != NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007237 }
7238 if (delete != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007239 xmlUnlinkNode(delete);
7240 xmlFreeNode(delete);
7241 delete = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007242 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00007243}
Daniel Veillard6eadf632003-01-23 18:29:16 +00007244
Daniel Veillardc5312d72003-02-21 17:14:10 +00007245/**
7246 * xmlRelaxNGCleanupDoc:
7247 * @ctxt: a Relax-NG parser context
7248 * @doc: an xmldocPtr document pointer
7249 *
7250 * Cleanup the document from unwanted nodes for parsing, resolve
7251 * Include and externalRef lookups.
7252 *
7253 * Returns the cleaned up document or NULL in case of error
7254 */
7255static xmlDocPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007256xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7257{
Daniel Veillardc5312d72003-02-21 17:14:10 +00007258 xmlNodePtr root;
7259
7260 /*
7261 * Extract the root
7262 */
7263 root = xmlDocGetRootElement(doc);
7264 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007265 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7266 ctxt->URL, NULL);
Daniel Veillardc5312d72003-02-21 17:14:10 +00007267 return (NULL);
7268 }
7269 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillard4c004142003-10-07 11:33:24 +00007270 return (doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007271}
7272
7273/**
7274 * xmlRelaxNGParse:
7275 * @ctxt: a Relax-NG parser context
7276 *
7277 * parse a schema definition resource and build an internal
7278 * XML Shema struture which can be used to validate instances.
7279 * *WARNING* this interface is highly subject to change
7280 *
7281 * Returns the internal XML RelaxNG structure built from the resource or
7282 * NULL in case of error
7283 */
7284xmlRelaxNGPtr
7285xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7286{
7287 xmlRelaxNGPtr ret = NULL;
7288 xmlDocPtr doc;
7289 xmlNodePtr root;
7290
7291 xmlRelaxNGInitTypes();
7292
7293 if (ctxt == NULL)
7294 return (NULL);
7295
7296 /*
7297 * First step is to parse the input document into an DOM/Infoset
7298 */
7299 if (ctxt->URL != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007300 doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007301 if (doc == NULL) {
7302 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7303 "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7304 NULL);
7305 return (NULL);
7306 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007307 } else if (ctxt->buffer != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007308 doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007309 if (doc == NULL) {
7310 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7311 "xmlRelaxNGParse: could not parse schemas\n", NULL,
7312 NULL);
7313 return (NULL);
7314 }
7315 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7316 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard33300b42003-04-17 09:09:19 +00007317 } else if (ctxt->document != NULL) {
7318 doc = ctxt->document;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007319 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007320 xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7321 "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7322 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007323 }
7324 ctxt->document = doc;
7325
7326 /*
7327 * Some preprocessing of the document content
7328 */
7329 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7330 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007331 xmlFreeDoc(ctxt->document);
7332 ctxt->document = NULL;
7333 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007334 }
7335
Daniel Veillard6eadf632003-01-23 18:29:16 +00007336 /*
7337 * Then do the parsing for good
7338 */
7339 root = xmlDocGetRootElement(doc);
7340 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007341 xmlRngPErr(ctxt, (xmlNodePtr) doc,
7342 XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7343 ctxt->URL, NULL);
7344 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007345 return (NULL);
7346 }
7347 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007348 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007349 xmlFreeDoc(doc);
7350 return (NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007351 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007352
7353 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007354 * Check the ref/defines links
7355 */
7356 /*
7357 * try to preprocess interleaves
7358 */
7359 if (ctxt->interleaves != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007360 xmlHashScan(ctxt->interleaves,
7361 (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007362 }
7363
7364 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007365 * if there was a parsing error return NULL
7366 */
7367 if (ctxt->nbErrors > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007368 xmlRelaxNGFree(ret);
7369 ctxt->document = NULL;
7370 xmlFreeDoc(doc);
7371 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007372 }
7373
7374 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007375 * try to compile (parts of) the schemas
7376 */
Daniel Veillardce192eb2003-04-16 15:58:05 +00007377 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7378 if (ret->topgrammar->start->type != XML_RELAXNG_START) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007379 xmlRelaxNGDefinePtr def;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007380
Daniel Veillard4c004142003-10-07 11:33:24 +00007381 def = xmlRelaxNGNewDefine(ctxt, NULL);
7382 if (def != NULL) {
7383 def->type = XML_RELAXNG_START;
7384 def->content = ret->topgrammar->start;
7385 ret->topgrammar->start = def;
7386 }
7387 }
7388 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007389 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007390
7391 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007392 * Transfer the pointer for cleanup at the schema level.
7393 */
7394 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007395 ctxt->document = NULL;
7396 ret->documents = ctxt->documents;
7397 ctxt->documents = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007398
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007399 ret->includes = ctxt->includes;
7400 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007401 ret->defNr = ctxt->defNr;
7402 ret->defTab = ctxt->defTab;
7403 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007404 if (ctxt->idref == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00007405 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007406
7407 return (ret);
7408}
Daniel Veillard4c004142003-10-07 11:33:24 +00007409
Daniel Veillard6eadf632003-01-23 18:29:16 +00007410/**
7411 * xmlRelaxNGSetParserErrors:
7412 * @ctxt: a Relax-NG validation context
7413 * @err: the error callback
7414 * @warn: the warning callback
7415 * @ctx: contextual data for the callbacks
7416 *
7417 * Set the callback functions used to handle errors for a validation context
7418 */
7419void
7420xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007421 xmlRelaxNGValidityErrorFunc err,
7422 xmlRelaxNGValidityWarningFunc warn, void *ctx)
7423{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007424 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007425 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007426 ctxt->error = err;
7427 ctxt->warning = warn;
7428 ctxt->userData = ctx;
7429}
Daniel Veillard409a8142003-07-18 15:16:57 +00007430
7431/**
7432 * xmlRelaxNGGetParserErrors:
7433 * @ctxt: a Relax-NG validation context
7434 * @err: the error callback result
7435 * @warn: the warning callback result
7436 * @ctx: contextual data for the callbacks result
7437 *
7438 * Get the callback information used to handle errors for a validation context
7439 *
7440 * Returns -1 in case of failure, 0 otherwise.
7441 */
7442int
7443xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007444 xmlRelaxNGValidityErrorFunc * err,
7445 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
7446{
Daniel Veillard409a8142003-07-18 15:16:57 +00007447 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007448 return (-1);
7449 if (err != NULL)
7450 *err = ctxt->error;
7451 if (warn != NULL)
7452 *warn = ctxt->warning;
7453 if (ctx != NULL)
7454 *ctx = ctxt->userData;
7455 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +00007456}
7457
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007458#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard4c004142003-10-07 11:33:24 +00007459
Daniel Veillard6eadf632003-01-23 18:29:16 +00007460/************************************************************************
7461 * *
7462 * Dump back a compiled form *
7463 * *
7464 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007465static void xmlRelaxNGDumpDefine(FILE * output,
7466 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007467
7468/**
7469 * xmlRelaxNGDumpDefines:
7470 * @output: the file output
7471 * @defines: a list of define structures
7472 *
7473 * Dump a RelaxNG structure back
7474 */
7475static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007476xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
7477{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007478 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007479 xmlRelaxNGDumpDefine(output, defines);
7480 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007481 }
7482}
7483
7484/**
7485 * xmlRelaxNGDumpDefine:
7486 * @output: the file output
7487 * @define: a define structure
7488 *
7489 * Dump a RelaxNG structure back
7490 */
7491static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007492xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
7493{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007494 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007495 return;
7496 switch (define->type) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007497 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00007498 fprintf(output, "<empty/>\n");
7499 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007500 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00007501 fprintf(output, "<notAllowed/>\n");
7502 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007503 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007504 fprintf(output, "<text/>\n");
7505 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007506 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007507 fprintf(output, "<element>\n");
7508 if (define->name != NULL) {
7509 fprintf(output, "<name");
7510 if (define->ns != NULL)
7511 fprintf(output, " ns=\"%s\"", define->ns);
7512 fprintf(output, ">%s</name>\n", define->name);
7513 }
7514 xmlRelaxNGDumpDefines(output, define->attrs);
7515 xmlRelaxNGDumpDefines(output, define->content);
7516 fprintf(output, "</element>\n");
7517 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007518 case XML_RELAXNG_LIST:
Daniel Veillard4c004142003-10-07 11:33:24 +00007519 fprintf(output, "<list>\n");
7520 xmlRelaxNGDumpDefines(output, define->content);
7521 fprintf(output, "</list>\n");
7522 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007523 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007524 fprintf(output, "<oneOrMore>\n");
7525 xmlRelaxNGDumpDefines(output, define->content);
7526 fprintf(output, "</oneOrMore>\n");
7527 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007528 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007529 fprintf(output, "<zeroOrMore>\n");
7530 xmlRelaxNGDumpDefines(output, define->content);
7531 fprintf(output, "</zeroOrMore>\n");
7532 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007533 case XML_RELAXNG_CHOICE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007534 fprintf(output, "<choice>\n");
7535 xmlRelaxNGDumpDefines(output, define->content);
7536 fprintf(output, "</choice>\n");
7537 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007538 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00007539 fprintf(output, "<group>\n");
7540 xmlRelaxNGDumpDefines(output, define->content);
7541 fprintf(output, "</group>\n");
7542 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007543 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007544 fprintf(output, "<interleave>\n");
7545 xmlRelaxNGDumpDefines(output, define->content);
7546 fprintf(output, "</interleave>\n");
7547 break;
7548 case XML_RELAXNG_OPTIONAL:
7549 fprintf(output, "<optional>\n");
7550 xmlRelaxNGDumpDefines(output, define->content);
7551 fprintf(output, "</optional>\n");
7552 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007553 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007554 fprintf(output, "<attribute>\n");
7555 xmlRelaxNGDumpDefines(output, define->content);
7556 fprintf(output, "</attribute>\n");
7557 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007558 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007559 fprintf(output, "<define");
7560 if (define->name != NULL)
7561 fprintf(output, " name=\"%s\"", define->name);
7562 fprintf(output, ">\n");
7563 xmlRelaxNGDumpDefines(output, define->content);
7564 fprintf(output, "</define>\n");
7565 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007566 case XML_RELAXNG_REF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007567 fprintf(output, "<ref");
7568 if (define->name != NULL)
7569 fprintf(output, " name=\"%s\"", define->name);
7570 fprintf(output, ">\n");
7571 xmlRelaxNGDumpDefines(output, define->content);
7572 fprintf(output, "</ref>\n");
7573 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007574 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007575 fprintf(output, "<parentRef");
7576 if (define->name != NULL)
7577 fprintf(output, " name=\"%s\"", define->name);
7578 fprintf(output, ">\n");
7579 xmlRelaxNGDumpDefines(output, define->content);
7580 fprintf(output, "</parentRef>\n");
7581 break;
7582 case XML_RELAXNG_EXTERNALREF:
7583 fprintf(output, "<externalRef>");
7584 xmlRelaxNGDumpDefines(output, define->content);
7585 fprintf(output, "</externalRef>\n");
7586 break;
Daniel Veillarde431a272003-01-29 23:02:33 +00007587 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007588 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007589 TODO break;
7590 case XML_RELAXNG_START:
7591 case XML_RELAXNG_EXCEPT:
7592 case XML_RELAXNG_PARAM:
7593 TODO break;
7594 case XML_RELAXNG_NOOP:
7595 xmlRelaxNGDumpDefines(output, define->content);
7596 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007597 }
7598}
Daniel Veillard4c004142003-10-07 11:33:24 +00007599
Daniel Veillard6eadf632003-01-23 18:29:16 +00007600/**
7601 * xmlRelaxNGDumpGrammar:
7602 * @output: the file output
7603 * @grammar: a grammar structure
7604 * @top: is this a top grammar
7605 *
7606 * Dump a RelaxNG structure back
7607 */
7608static void
7609xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7610{
7611 if (grammar == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007612 return;
7613
Daniel Veillard6eadf632003-01-23 18:29:16 +00007614 fprintf(output, "<grammar");
7615 if (top)
Daniel Veillard4c004142003-10-07 11:33:24 +00007616 fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7617 switch (grammar->combine) {
7618 case XML_RELAXNG_COMBINE_UNDEFINED:
7619 break;
7620 case XML_RELAXNG_COMBINE_CHOICE:
7621 fprintf(output, " combine=\"choice\"");
7622 break;
7623 case XML_RELAXNG_COMBINE_INTERLEAVE:
7624 fprintf(output, " combine=\"interleave\"");
7625 break;
7626 default:
7627 fprintf(output, " <!-- invalid combine value -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007628 }
7629 fprintf(output, ">\n");
7630 if (grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007631 fprintf(output, " <!-- grammar had no start -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007632 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007633 fprintf(output, "<start>\n");
7634 xmlRelaxNGDumpDefine(output, grammar->start);
7635 fprintf(output, "</start>\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007636 }
7637 /* TODO ? Dump the defines ? */
7638 fprintf(output, "</grammar>\n");
7639}
7640
7641/**
7642 * xmlRelaxNGDump:
7643 * @output: the file output
7644 * @schema: a schema structure
7645 *
7646 * Dump a RelaxNG structure back
7647 */
7648void
7649xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7650{
7651 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007652 fprintf(output, "RelaxNG empty or failed to compile\n");
7653 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007654 }
7655 fprintf(output, "RelaxNG: ");
7656 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007657 fprintf(output, "no document\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007658 } else if (schema->doc->URL != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007659 fprintf(output, "%s\n", schema->doc->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007660 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007661 fprintf(output, "\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007662 }
7663 if (schema->topgrammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007664 fprintf(output, "RelaxNG has no top grammar\n");
7665 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007666 }
7667 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7668}
7669
Daniel Veillardfebcca42003-02-16 15:44:18 +00007670/**
7671 * xmlRelaxNGDumpTree:
7672 * @output: the file output
7673 * @schema: a schema structure
7674 *
7675 * Dump the transformed RelaxNG tree.
7676 */
7677void
7678xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7679{
7680 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007681 fprintf(output, "RelaxNG empty or failed to compile\n");
7682 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007683 }
7684 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007685 fprintf(output, "no document\n");
Daniel Veillardfebcca42003-02-16 15:44:18 +00007686 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007687 xmlDocDump(output, schema->doc);
Daniel Veillardfebcca42003-02-16 15:44:18 +00007688 }
7689}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007690#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardfebcca42003-02-16 15:44:18 +00007691
Daniel Veillard6eadf632003-01-23 18:29:16 +00007692/************************************************************************
7693 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007694 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007695 * *
7696 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007697static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7698 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007699
7700/**
7701 * xmlRelaxNGValidateCompiledCallback:
7702 * @exec: the regular expression instance
7703 * @token: the token which matched
7704 * @transdata: callback data, the define for the subelement if available
7705 @ @inputdata: callback data, the Relax NG validation context
7706 *
7707 * Handle the callback and if needed validate the element children.
7708 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007709static void
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007710xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00007711 const xmlChar * token,
7712 void *transdata, void *inputdata)
7713{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007714 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7715 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7716 int ret;
7717
7718#ifdef DEBUG_COMPILE
7719 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007720 "Compiled callback for: '%s'\n", token);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007721#endif
7722 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007723 fprintf(stderr, "callback on %s missing context\n", token);
7724 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7725 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7726 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007727 }
7728 if (define == NULL) {
7729 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007730 return;
7731 fprintf(stderr, "callback on %s missing define\n", token);
7732 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7733 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7734 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007735 }
7736 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007737 fprintf(stderr, "callback on %s missing info\n", token);
7738 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7739 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7740 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007741 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007742 fprintf(stderr, "callback on %s define is not element\n", token);
7743 if (ctxt->errNo == XML_RELAXNG_OK)
7744 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7745 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007746 }
7747 ret = xmlRelaxNGValidateDefinition(ctxt, define);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007748 if (ret != 0)
7749 ctxt->perr = ret;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007750}
7751
7752/**
7753 * xmlRelaxNGValidateCompiledContent:
7754 * @ctxt: the RelaxNG validation context
7755 * @regexp: the regular expression as compiled
7756 * @content: list of children to test against the regexp
7757 *
7758 * Validate the content model of an element or start using the regexp
7759 *
7760 * Returns 0 in case of success, -1 in case of error.
7761 */
7762static int
7763xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007764 xmlRegexpPtr regexp, xmlNodePtr content)
7765{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007766 xmlRegExecCtxtPtr exec;
7767 xmlNodePtr cur;
Daniel Veillard62163602003-04-17 09:36:38 +00007768 int ret = 0;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007769 int oldperr = ctxt->perr;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007770
7771 if ((ctxt == NULL) || (regexp == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00007772 return (-1);
7773 exec = xmlRegNewExecCtxt(regexp,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007774 xmlRelaxNGValidateCompiledCallback, ctxt);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007775 ctxt->perr = 0;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007776 cur = content;
7777 while (cur != NULL) {
7778 ctxt->state->seq = cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00007779 switch (cur->type) {
7780 case XML_TEXT_NODE:
7781 case XML_CDATA_SECTION_NODE:
7782 if (xmlIsBlankNode(cur))
7783 break;
7784 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7785 if (ret < 0) {
7786 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
7787 cur->parent->name);
7788 }
7789 break;
7790 case XML_ELEMENT_NODE:
7791 if (cur->ns != NULL) {
7792 ret = xmlRegExecPushString2(exec, cur->name,
7793 cur->ns->href, ctxt);
7794 } else {
7795 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7796 }
7797 if (ret < 0) {
7798 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7799 }
7800 break;
7801 default:
7802 break;
7803 }
7804 if (ret < 0)
7805 break;
7806 /*
7807 * Switch to next element
7808 */
7809 cur = cur->next;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007810 }
7811 ret = xmlRegExecPushString(exec, NULL, NULL);
7812 if (ret == 1) {
7813 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00007814 ctxt->state->seq = NULL;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007815 } else if (ret == 0) {
7816 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00007817 * TODO: get some of the names needed to exit the current state of exec
7818 */
7819 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7820 ret = -1;
7821 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7822 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007823 } else {
7824 ret = -1;
7825 }
7826 xmlRegFreeExecCtxt(exec);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007827 /*
7828 * There might be content model errors outside of the pure
7829 * regexp validation, e.g. for attribute values.
7830 */
7831 if ((ret == 0) && (ctxt->perr != 0)) {
7832 ret = ctxt->perr;
7833 }
7834 ctxt->perr = oldperr;
Daniel Veillard4c004142003-10-07 11:33:24 +00007835 return (ret);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007836}
7837
7838/************************************************************************
7839 * *
7840 * Progressive validation of when possible *
7841 * *
7842 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007843static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7844 xmlRelaxNGDefinePtr defines);
7845static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
William M. Brack272693c2003-11-14 16:20:34 +00007846 int dolog);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00007847static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007848
7849/**
7850 * xmlRelaxNGElemPush:
7851 * @ctxt: the validation context
7852 * @exec: the regexp runtime for the new content model
7853 *
7854 * Push a new regexp for the current node content model on the stack
7855 *
7856 * Returns 0 in case of success and -1 in case of error.
7857 */
7858static int
Daniel Veillard4c004142003-10-07 11:33:24 +00007859xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
7860{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007861 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007862 ctxt->elemMax = 10;
7863 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7864 sizeof
7865 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007866 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007867 xmlRngVErrMemory(ctxt, "validating\n");
7868 return (-1);
7869 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007870 }
7871 if (ctxt->elemNr >= ctxt->elemMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007872 ctxt->elemMax *= 2;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007873 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00007874 ctxt->elemMax *
7875 sizeof
7876 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007877 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007878 xmlRngVErrMemory(ctxt, "validating\n");
7879 return (-1);
7880 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007881 }
7882 ctxt->elemTab[ctxt->elemNr++] = exec;
7883 ctxt->elem = exec;
Daniel Veillard4c004142003-10-07 11:33:24 +00007884 return (0);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007885}
7886
7887/**
7888 * xmlRelaxNGElemPop:
7889 * @ctxt: the validation context
7890 *
7891 * Pop the regexp of the current node content model from the stack
7892 *
7893 * Returns the exec or NULL if empty
7894 */
7895static xmlRegExecCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007896xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
7897{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007898 xmlRegExecCtxtPtr ret;
7899
Daniel Veillard4c004142003-10-07 11:33:24 +00007900 if (ctxt->elemNr <= 0)
7901 return (NULL);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007902 ctxt->elemNr--;
7903 ret = ctxt->elemTab[ctxt->elemNr];
7904 ctxt->elemTab[ctxt->elemNr] = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007905 if (ctxt->elemNr > 0)
Daniel Veillardf4e55762003-04-15 23:32:22 +00007906 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7907 else
Daniel Veillard4c004142003-10-07 11:33:24 +00007908 ctxt->elem = NULL;
7909 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007910}
7911
7912/**
7913 * xmlRelaxNGValidateProgressiveCallback:
7914 * @exec: the regular expression instance
7915 * @token: the token which matched
7916 * @transdata: callback data, the define for the subelement if available
7917 @ @inputdata: callback data, the Relax NG validation context
7918 *
7919 * Handle the callback and if needed validate the element children.
7920 * some of the in/out informations are passed via the context in @inputdata.
7921 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007922static void
7923xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
7924 ATTRIBUTE_UNUSED,
7925 const xmlChar * token,
7926 void *transdata, void *inputdata)
7927{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007928 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7929 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007930 xmlRelaxNGValidStatePtr state, oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007931 xmlNodePtr node = ctxt->pnode;
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00007932 int ret = 0, oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007933
7934#ifdef DEBUG_PROGRESSIVE
7935 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007936 "Progressive callback for: '%s'\n", token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007937#endif
7938 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007939 fprintf(stderr, "callback on %s missing context\n", token);
7940 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007941 }
7942 ctxt->pstate = 1;
7943 if (define == NULL) {
7944 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007945 return;
7946 fprintf(stderr, "callback on %s missing define\n", token);
7947 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7948 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7949 ctxt->pstate = -1;
7950 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007951 }
7952 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007953 fprintf(stderr, "callback on %s missing info\n", token);
7954 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7955 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7956 ctxt->pstate = -1;
7957 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007958 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007959 fprintf(stderr, "callback on %s define is not element\n", token);
7960 if (ctxt->errNo == XML_RELAXNG_OK)
7961 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7962 ctxt->pstate = -1;
7963 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007964 }
7965 if (node->type != XML_ELEMENT_NODE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007966 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
7967 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7968 xmlRelaxNGDumpValidError(ctxt);
7969 ctxt->pstate = -1;
7970 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007971 }
7972 if (define->contModel == NULL) {
7973 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00007974 * this node cannot be validated in a streamable fashion
7975 */
Daniel Veillardf4e55762003-04-15 23:32:22 +00007976#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00007977 xmlGenericError(xmlGenericErrorContext,
7978 "Element '%s' validation is not streamable\n",
7979 token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007980#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00007981 ctxt->pstate = 0;
7982 ctxt->pdef = define;
7983 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007984 }
7985 exec = xmlRegNewExecCtxt(define->contModel,
Daniel Veillard4c004142003-10-07 11:33:24 +00007986 xmlRelaxNGValidateProgressiveCallback, ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007987 if (exec == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007988 ctxt->pstate = -1;
7989 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007990 }
7991 xmlRelaxNGElemPush(ctxt, exec);
7992
7993 /*
7994 * Validate the attributes part of the content.
7995 */
7996 state = xmlRelaxNGNewValidState(ctxt, node);
7997 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007998 ctxt->pstate = -1;
7999 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008000 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008001 oldstate = ctxt->state;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008002 ctxt->state = state;
8003 if (define->attrs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008004 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8005 if (ret != 0) {
8006 ctxt->pstate = -1;
8007 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8008 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00008009 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008010 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008011 ctxt->state->seq = NULL;
8012 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
8013 if (ret != 0) {
8014 ctxt->pstate = -1;
8015 }
8016 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008017 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008018 int tmp = -1, i;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008019
8020 oldflags = ctxt->flags;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008021
Daniel Veillard4c004142003-10-07 11:33:24 +00008022 for (i = 0; i < ctxt->states->nbState; i++) {
8023 state = ctxt->states->tabState[i];
8024 ctxt->state = state;
8025 ctxt->state->seq = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008026
Daniel Veillard4c004142003-10-07 11:33:24 +00008027 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
8028 tmp = 0;
8029 break;
8030 }
8031 }
8032 if (tmp != 0) {
8033 /*
8034 * validation error, log the message for the "best" one
8035 */
8036 ctxt->flags |= FLAGS_IGNORABLE;
8037 xmlRelaxNGLogBestError(ctxt);
8038 }
8039 for (i = 0; i < ctxt->states->nbState; i++) {
8040 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
8041 }
8042 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8043 ctxt->states = NULL;
8044 if ((ret == 0) && (tmp == -1))
8045 ctxt->pstate = -1;
8046 ctxt->flags = oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008047 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008048 if (ctxt->pstate == -1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008049 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8050 xmlRelaxNGDumpValidError(ctxt);
8051 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008052 }
8053 ctxt->state = oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008054}
8055
8056/**
8057 * xmlRelaxNGValidatePushElement:
8058 * @ctxt: the validation context
8059 * @doc: a document instance
8060 * @elem: an element instance
8061 *
8062 * Push a new element start on the RelaxNG validation stack.
8063 *
8064 * returns 1 if no validation problem was found or 0 if validating the
8065 * element requires a full node, and -1 in case of error.
8066 */
8067int
Daniel Veillard33300b42003-04-17 09:09:19 +00008068xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
8069 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00008070 xmlNodePtr elem)
8071{
8072 int ret = 1;
8073
8074 if ((ctxt == NULL) || (elem == NULL))
8075 return (-1);
8076
8077#ifdef DEBUG_PROGRESSIVE
8078 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
8079#endif
8080 if (ctxt->elem == 0) {
8081 xmlRelaxNGPtr schema;
8082 xmlRelaxNGGrammarPtr grammar;
8083 xmlRegExecCtxtPtr exec;
8084 xmlRelaxNGDefinePtr define;
8085
8086 schema = ctxt->schema;
8087 if (schema == NULL) {
8088 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8089 return (-1);
8090 }
8091 grammar = schema->topgrammar;
8092 if ((grammar == NULL) || (grammar->start == NULL)) {
8093 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8094 return (-1);
8095 }
8096 define = grammar->start;
8097 if (define->contModel == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008098 ctxt->pdef = define;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008099 return (0);
8100 }
8101 exec = xmlRegNewExecCtxt(define->contModel,
8102 xmlRelaxNGValidateProgressiveCallback,
8103 ctxt);
8104 if (exec == NULL) {
8105 return (-1);
8106 }
8107 xmlRelaxNGElemPush(ctxt, exec);
8108 }
8109 ctxt->pnode = elem;
8110 ctxt->pstate = 0;
8111 if (elem->ns != NULL) {
8112 ret =
8113 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8114 ctxt);
8115 } else {
8116 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8117 }
8118 if (ret < 0) {
8119 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8120 } else {
8121 if (ctxt->pstate == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008122 ret = 0;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008123 else if (ctxt->pstate < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008124 ret = -1;
8125 else
8126 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008127 }
8128#ifdef DEBUG_PROGRESSIVE
8129 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008130 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8131 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008132#endif
8133 return (ret);
8134}
8135
8136/**
8137 * xmlRelaxNGValidatePushCData:
8138 * @ctxt: the RelaxNG validation context
8139 * @data: some character data read
8140 * @len: the lenght of the data
8141 *
8142 * check the CData parsed for validation in the current stack
8143 *
8144 * returns 1 if no validation problem was found or -1 otherwise
8145 */
8146int
8147xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00008148 const xmlChar * data, int len ATTRIBUTE_UNUSED)
Daniel Veillardf4e55762003-04-15 23:32:22 +00008149{
8150 int ret = 1;
8151
8152 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8153 return (-1);
8154
8155#ifdef DEBUG_PROGRESSIVE
8156 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8157#endif
8158
8159 while (*data != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008160 if (!IS_BLANK_CH(*data))
Daniel Veillardf4e55762003-04-15 23:32:22 +00008161 break;
8162 data++;
8163 }
8164 if (*data == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008165 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008166
8167 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8168 if (ret < 0) {
Daniel Veillard33300b42003-04-17 09:09:19 +00008169 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008170#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008171 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008172#endif
8173
Daniel Veillard4c004142003-10-07 11:33:24 +00008174 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008175 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008176 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008177}
8178
8179/**
8180 * xmlRelaxNGValidatePopElement:
8181 * @ctxt: the RelaxNG validation context
8182 * @doc: a document instance
8183 * @elem: an element instance
8184 *
8185 * Pop the element end from the RelaxNG validation stack.
8186 *
8187 * returns 1 if no validation problem was found or 0 otherwise
8188 */
8189int
8190xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8191 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008192 xmlNodePtr elem)
8193{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008194 int ret;
8195 xmlRegExecCtxtPtr exec;
8196
Daniel Veillard4c004142003-10-07 11:33:24 +00008197 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
8198 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008199#ifdef DEBUG_PROGRESSIVE
8200 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8201#endif
8202 /*
8203 * verify that we reached a terminal state of the content model.
8204 */
8205 exec = xmlRelaxNGElemPop(ctxt);
8206 ret = xmlRegExecPushString(exec, NULL, NULL);
8207 if (ret == 0) {
8208 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008209 * TODO: get some of the names needed to exit the current state of exec
8210 */
8211 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8212 ret = -1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008213 } else if (ret < 0) {
8214 ret = -1;
8215 } else {
8216 ret = 1;
8217 }
8218 xmlRegFreeExecCtxt(exec);
8219#ifdef DEBUG_PROGRESSIVE
8220 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008221 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8222 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008223#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008224 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008225}
8226
8227/**
8228 * xmlRelaxNGValidateFullElement:
8229 * @ctxt: the validation context
8230 * @doc: a document instance
8231 * @elem: an element instance
8232 *
8233 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8234 * 0 and the content of the node has been expanded.
8235 *
8236 * returns 1 if no validation problem was found or -1 in case of error.
8237 */
8238int
Daniel Veillard33300b42003-04-17 09:09:19 +00008239xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8240 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008241 xmlNodePtr elem)
8242{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008243 int ret;
8244 xmlRelaxNGValidStatePtr state;
8245
Daniel Veillard4c004142003-10-07 11:33:24 +00008246 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
8247 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008248#ifdef DEBUG_PROGRESSIVE
8249 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8250#endif
8251 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8252 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008253 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008254 }
8255 state->seq = elem;
8256 ctxt->state = state;
8257 ctxt->errNo = XML_RELAXNG_OK;
8258 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
Daniel Veillard4c004142003-10-07 11:33:24 +00008259 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
8260 ret = -1;
8261 else
8262 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008263 xmlRelaxNGFreeValidState(ctxt, state);
8264 ctxt->state = NULL;
8265#ifdef DEBUG_PROGRESSIVE
8266 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008267 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8268 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008269#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008270 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008271}
8272
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008273/************************************************************************
8274 * *
8275 * Generic interpreted validation implementation *
8276 * *
8277 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00008278static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8279 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008280
8281/**
8282 * xmlRelaxNGSkipIgnored:
8283 * @ctxt: a schema validation context
8284 * @node: the top node.
8285 *
8286 * Skip ignorable nodes in that context
8287 *
8288 * Returns the new sibling or NULL in case of error.
8289 */
8290static xmlNodePtr
8291xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008292 xmlNodePtr node)
8293{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008294 /*
8295 * TODO complete and handle entities
8296 */
8297 while ((node != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00008298 ((node->type == XML_COMMENT_NODE) ||
8299 (node->type == XML_PI_NODE) ||
William M. Brack7217c862004-03-15 02:43:56 +00008300 (node->type == XML_XINCLUDE_START) ||
8301 (node->type == XML_XINCLUDE_END) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00008302 (((node->type == XML_TEXT_NODE) ||
8303 (node->type == XML_CDATA_SECTION_NODE)) &&
8304 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8305 (IS_BLANK_NODE(node)))))) {
8306 node = node->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008307 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008308 return (node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008309}
8310
8311/**
Daniel Veillardedc91922003-01-26 00:52:04 +00008312 * xmlRelaxNGNormalize:
8313 * @ctxt: a schema validation context
8314 * @str: the string to normalize
8315 *
8316 * Implements the normalizeWhiteSpace( s ) function from
8317 * section 6.2.9 of the spec
8318 *
8319 * Returns the new string or NULL in case of error.
8320 */
8321static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00008322xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
8323{
Daniel Veillardedc91922003-01-26 00:52:04 +00008324 xmlChar *ret, *p;
8325 const xmlChar *tmp;
8326 int len;
Daniel Veillard4c004142003-10-07 11:33:24 +00008327
Daniel Veillardedc91922003-01-26 00:52:04 +00008328 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008329 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008330 tmp = str;
Daniel Veillard4c004142003-10-07 11:33:24 +00008331 while (*tmp != 0)
8332 tmp++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008333 len = tmp - str;
8334
Daniel Veillard3c908dc2003-04-19 00:07:51 +00008335 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
Daniel Veillardedc91922003-01-26 00:52:04 +00008336 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008337 xmlRngVErrMemory(ctxt, "validating\n");
8338 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008339 }
8340 p = ret;
William M. Brack76e95df2003-10-18 16:20:14 +00008341 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008342 str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008343 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008344 if (IS_BLANK_CH(*str)) {
8345 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008346 str++;
8347 if (*str == 0)
8348 break;
8349 *p++ = ' ';
8350 } else
8351 *p++ = *str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008352 }
8353 *p = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00008354 return (ret);
Daniel Veillardedc91922003-01-26 00:52:04 +00008355}
8356
8357/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008358 * xmlRelaxNGValidateDatatype:
8359 * @ctxt: a Relax-NG validation context
8360 * @value: the string value
8361 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008362 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008363 *
8364 * Validate the given value against the dataype
8365 *
8366 * Returns 0 if the validation succeeded or an error code.
8367 */
8368static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008369xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
8370 const xmlChar * value,
8371 xmlRelaxNGDefinePtr define, xmlNodePtr node)
8372{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008373 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008374 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008375 void *result = NULL;
8376 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008377
8378 if ((define == NULL) || (define->data == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008379 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008380 }
8381 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008382 if (lib->check != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008383 if ((define->attrs != NULL) &&
8384 (define->attrs->type == XML_RELAXNG_PARAM)) {
8385 ret =
8386 lib->check(lib->data, define->name, value, &result, node);
8387 } else {
8388 ret = lib->check(lib->data, define->name, value, NULL, node);
8389 }
8390 } else
8391 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008392 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008393 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8394 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8395 lib->freef(lib->data, result);
8396 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008397 } else if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008398 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008399 } else if (ret == 2) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008400 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008401 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008402 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8403 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008404 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008405 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008406 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008407 if (lib->facet != NULL) {
8408 tmp = lib->facet(lib->data, define->name, cur->name,
8409 cur->value, value, result);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008410 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008411 ret = -1;
8412 }
8413 cur = cur->next;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008414 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008415 if ((ret == 0) && (define->content != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008416 const xmlChar *oldvalue, *oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008417
Daniel Veillard4c004142003-10-07 11:33:24 +00008418 oldvalue = ctxt->state->value;
8419 oldendvalue = ctxt->state->endvalue;
8420 ctxt->state->value = (xmlChar *) value;
8421 ctxt->state->endvalue = NULL;
8422 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8423 ctxt->state->value = (xmlChar *) oldvalue;
8424 ctxt->state->endvalue = (xmlChar *) oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008425 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008426 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00008427 lib->freef(lib->data, result);
8428 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008429}
8430
8431/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008432 * xmlRelaxNGNextValue:
8433 * @ctxt: a Relax-NG validation context
8434 *
8435 * Skip to the next value when validating within a list
8436 *
8437 * Returns 0 if the operation succeeded or an error code.
8438 */
8439static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008440xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
8441{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008442 xmlChar *cur;
8443
8444 cur = ctxt->state->value;
8445 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008446 ctxt->state->value = NULL;
8447 ctxt->state->endvalue = NULL;
8448 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008449 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008450 while (*cur != 0)
8451 cur++;
8452 while ((cur != ctxt->state->endvalue) && (*cur == 0))
8453 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008454 if (cur == ctxt->state->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00008455 ctxt->state->value = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008456 else
Daniel Veillard4c004142003-10-07 11:33:24 +00008457 ctxt->state->value = cur;
8458 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008459}
8460
8461/**
8462 * xmlRelaxNGValidateValueList:
8463 * @ctxt: a Relax-NG validation context
8464 * @defines: the list of definitions to verify
8465 *
8466 * Validate the given set of definitions for the current value
8467 *
8468 * Returns 0 if the validation succeeded or an error code.
8469 */
8470static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008471xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8472 xmlRelaxNGDefinePtr defines)
8473{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008474 int ret = 0;
8475
8476 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008477 ret = xmlRelaxNGValidateValue(ctxt, defines);
8478 if (ret != 0)
8479 break;
8480 defines = defines->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008481 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008482 return (ret);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008483}
8484
8485/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008486 * xmlRelaxNGValidateValue:
8487 * @ctxt: a Relax-NG validation context
8488 * @define: the definition to verify
8489 *
8490 * Validate the given definition for the current value
8491 *
8492 * Returns 0 if the validation succeeded or an error code.
8493 */
8494static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008495xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8496 xmlRelaxNGDefinePtr define)
8497{
Daniel Veillardedc91922003-01-26 00:52:04 +00008498 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008499 xmlChar *value;
8500
8501 value = ctxt->state->value;
8502 switch (define->type) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008503 case XML_RELAXNG_EMPTY:{
8504 if ((value != NULL) && (value[0] != 0)) {
8505 int idx = 0;
Daniel Veillardd4310742003-02-18 21:12:46 +00008506
William M. Brack76e95df2003-10-18 16:20:14 +00008507 while (IS_BLANK_CH(value[idx]))
Daniel Veillard4c004142003-10-07 11:33:24 +00008508 idx++;
8509 if (value[idx] != 0)
8510 ret = -1;
8511 }
8512 break;
8513 }
8514 case XML_RELAXNG_TEXT:
8515 break;
8516 case XML_RELAXNG_VALUE:{
8517 if (!xmlStrEqual(value, define->value)) {
8518 if (define->name != NULL) {
8519 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillardedc91922003-01-26 00:52:04 +00008520
Daniel Veillard4c004142003-10-07 11:33:24 +00008521 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8522 if ((lib != NULL) && (lib->comp != NULL)) {
8523 ret = lib->comp(lib->data, define->name,
8524 define->value, define->node,
8525 (void *) define->attrs,
8526 value, ctxt->state->node);
8527 } else
8528 ret = -1;
8529 if (ret < 0) {
8530 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
8531 define->name);
8532 return (-1);
8533 } else if (ret == 1) {
8534 ret = 0;
8535 } else {
8536 ret = -1;
8537 }
8538 } else {
8539 xmlChar *nval, *nvalue;
Daniel Veillardedc91922003-01-26 00:52:04 +00008540
Daniel Veillard4c004142003-10-07 11:33:24 +00008541 /*
8542 * TODO: trivial optimizations are possible by
8543 * computing at compile-time
8544 */
8545 nval = xmlRelaxNGNormalize(ctxt, define->value);
8546 nvalue = xmlRelaxNGNormalize(ctxt, value);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008547
Daniel Veillard4c004142003-10-07 11:33:24 +00008548 if ((nval == NULL) || (nvalue == NULL) ||
8549 (!xmlStrEqual(nval, nvalue)))
8550 ret = -1;
8551 if (nval != NULL)
8552 xmlFree(nval);
8553 if (nvalue != NULL)
8554 xmlFree(nvalue);
8555 }
8556 }
8557 if (ret == 0)
8558 xmlRelaxNGNextValue(ctxt);
8559 break;
8560 }
8561 case XML_RELAXNG_DATATYPE:{
8562 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8563 ctxt->state->seq);
8564 if (ret == 0)
8565 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008566
Daniel Veillard4c004142003-10-07 11:33:24 +00008567 break;
8568 }
8569 case XML_RELAXNG_CHOICE:{
8570 xmlRelaxNGDefinePtr list = define->content;
8571 xmlChar *oldvalue;
8572
8573 oldflags = ctxt->flags;
8574 ctxt->flags |= FLAGS_IGNORABLE;
8575
8576 oldvalue = ctxt->state->value;
8577 while (list != NULL) {
8578 ret = xmlRelaxNGValidateValue(ctxt, list);
8579 if (ret == 0) {
8580 break;
8581 }
8582 ctxt->state->value = oldvalue;
8583 list = list->next;
8584 }
8585 ctxt->flags = oldflags;
8586 if (ret != 0) {
8587 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8588 xmlRelaxNGDumpValidError(ctxt);
8589 } else {
8590 if (ctxt->errNr > 0)
8591 xmlRelaxNGPopErrors(ctxt, 0);
8592 }
8593 if (ret == 0)
8594 xmlRelaxNGNextValue(ctxt);
8595 break;
8596 }
8597 case XML_RELAXNG_LIST:{
8598 xmlRelaxNGDefinePtr list = define->content;
8599 xmlChar *oldvalue, *oldend, *val, *cur;
8600
Daniel Veillard416589a2003-02-17 17:25:42 +00008601#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008602 int nb_values = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008603#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008604
Daniel Veillard4c004142003-10-07 11:33:24 +00008605 oldvalue = ctxt->state->value;
8606 oldend = ctxt->state->endvalue;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008607
Daniel Veillard4c004142003-10-07 11:33:24 +00008608 val = xmlStrdup(oldvalue);
8609 if (val == NULL) {
8610 val = xmlStrdup(BAD_CAST "");
8611 }
8612 if (val == NULL) {
8613 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8614 return (-1);
8615 }
8616 cur = val;
8617 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008618 if (IS_BLANK_CH(*cur)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008619 *cur = 0;
8620 cur++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008621#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008622 nb_values++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008623#endif
William M. Brack76e95df2003-10-18 16:20:14 +00008624 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00008625 *cur++ = 0;
8626 } else
8627 cur++;
8628 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008629#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008630 xmlGenericError(xmlGenericErrorContext,
8631 "list value: '%s' found %d items\n",
8632 oldvalue, nb_values);
8633 nb_values = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008634#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008635 ctxt->state->endvalue = cur;
8636 cur = val;
8637 while ((*cur == 0) && (cur != ctxt->state->endvalue))
8638 cur++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008639
Daniel Veillard4c004142003-10-07 11:33:24 +00008640 ctxt->state->value = cur;
8641
8642 while (list != NULL) {
8643 if (ctxt->state->value == ctxt->state->endvalue)
8644 ctxt->state->value = NULL;
8645 ret = xmlRelaxNGValidateValue(ctxt, list);
8646 if (ret != 0) {
8647#ifdef DEBUG_LIST
8648 xmlGenericError(xmlGenericErrorContext,
8649 "Failed to validate value: '%s' with %d rule\n",
8650 ctxt->state->value, nb_values);
8651#endif
8652 break;
8653 }
8654#ifdef DEBUG_LIST
8655 nb_values++;
8656#endif
8657 list = list->next;
8658 }
8659
8660 if ((ret == 0) && (ctxt->state->value != NULL) &&
8661 (ctxt->state->value != ctxt->state->endvalue)) {
8662 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
8663 ctxt->state->value);
8664 ret = -1;
8665 }
8666 xmlFree(val);
8667 ctxt->state->value = oldvalue;
8668 ctxt->state->endvalue = oldend;
8669 break;
8670 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008671 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00008672 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8673 if (ret != 0) {
8674 break;
8675 }
8676 /* no break on purpose */
8677 case XML_RELAXNG_ZEROORMORE:{
8678 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008679
Daniel Veillard4c004142003-10-07 11:33:24 +00008680 oldflags = ctxt->flags;
8681 ctxt->flags |= FLAGS_IGNORABLE;
8682 cur = ctxt->state->value;
8683 temp = NULL;
8684 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8685 (temp != cur)) {
8686 temp = cur;
8687 ret =
8688 xmlRelaxNGValidateValueList(ctxt, define->content);
8689 if (ret != 0) {
8690 ctxt->state->value = temp;
8691 ret = 0;
8692 break;
8693 }
8694 cur = ctxt->state->value;
8695 }
8696 ctxt->flags = oldflags;
8697 if (ret != 0) {
8698 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8699 xmlRelaxNGDumpValidError(ctxt);
8700 } else {
8701 if (ctxt->errNr > 0)
8702 xmlRelaxNGPopErrors(ctxt, 0);
8703 }
8704 break;
8705 }
8706 case XML_RELAXNG_EXCEPT:{
8707 xmlRelaxNGDefinePtr list;
Daniel Veillard416589a2003-02-17 17:25:42 +00008708
Daniel Veillard4c004142003-10-07 11:33:24 +00008709 list = define->content;
8710 while (list != NULL) {
8711 ret = xmlRelaxNGValidateValue(ctxt, list);
8712 if (ret == 0) {
8713 ret = -1;
8714 break;
8715 } else
8716 ret = 0;
8717 list = list->next;
8718 }
8719 break;
8720 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008721 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008722 case XML_RELAXNG_GROUP:{
8723 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008724
Daniel Veillard4c004142003-10-07 11:33:24 +00008725 list = define->content;
8726 while (list != NULL) {
8727 ret = xmlRelaxNGValidateValue(ctxt, list);
8728 if (ret != 0) {
8729 ret = -1;
8730 break;
8731 } else
8732 ret = 0;
8733 list = list->next;
8734 }
8735 break;
8736 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008737 case XML_RELAXNG_REF:
8738 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008739 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8740 break;
8741 default:
8742 TODO ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008743 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008744 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008745}
8746
8747/**
8748 * xmlRelaxNGValidateValueContent:
8749 * @ctxt: a Relax-NG validation context
8750 * @defines: the list of definitions to verify
8751 *
8752 * Validate the given definitions for the current value
8753 *
8754 * Returns 0 if the validation succeeded or an error code.
8755 */
8756static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008757xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8758 xmlRelaxNGDefinePtr defines)
8759{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008760 int ret = 0;
8761
8762 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008763 ret = xmlRelaxNGValidateValue(ctxt, defines);
8764 if (ret != 0)
8765 break;
8766 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008767 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008768 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008769}
8770
8771/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008772 * xmlRelaxNGAttributeMatch:
8773 * @ctxt: a Relax-NG validation context
8774 * @define: the definition to check
8775 * @prop: the attribute
8776 *
8777 * Check if the attribute matches the definition nameClass
8778 *
8779 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8780 */
8781static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008782xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8783 xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
8784{
Daniel Veillardfd573f12003-03-16 17:52:32 +00008785 int ret;
8786
8787 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008788 if (!xmlStrEqual(define->name, prop->name))
8789 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008790 }
8791 if (define->ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008792 if (define->ns[0] == 0) {
8793 if (prop->ns != NULL)
8794 return (0);
8795 } else {
8796 if ((prop->ns == NULL) ||
8797 (!xmlStrEqual(define->ns, prop->ns->href)))
8798 return (0);
8799 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008800 }
8801 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008802 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008803 define = define->nameClass;
8804 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008805 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008806
Daniel Veillard4c004142003-10-07 11:33:24 +00008807 list = define->content;
8808 while (list != NULL) {
8809 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8810 if (ret == 1)
8811 return (0);
8812 if (ret < 0)
8813 return (ret);
8814 list = list->next;
8815 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008816 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008817 TODO}
8818 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008819}
8820
8821/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008822 * xmlRelaxNGValidateAttribute:
8823 * @ctxt: a Relax-NG validation context
8824 * @define: the definition to verify
8825 *
8826 * Validate the given attribute definition for that node
8827 *
8828 * Returns 0 if the validation succeeded or an error code.
8829 */
8830static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008831xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8832 xmlRelaxNGDefinePtr define)
8833{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008834 int ret = 0, i;
8835 xmlChar *value, *oldvalue;
8836 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008837 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008838
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008839 if (ctxt->state->nbAttrLeft <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008840 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008841 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008842 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8843 tmp = ctxt->state->attrs[i];
8844 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8845 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8846 (tmp->ns == NULL)) ||
8847 ((tmp->ns != NULL) &&
8848 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8849 prop = tmp;
8850 break;
8851 }
8852 }
8853 }
8854 if (prop != NULL) {
8855 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8856 oldvalue = ctxt->state->value;
8857 oldseq = ctxt->state->seq;
8858 ctxt->state->seq = (xmlNodePtr) prop;
8859 ctxt->state->value = value;
8860 ctxt->state->endvalue = NULL;
8861 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8862 if (ctxt->state->value != NULL)
8863 value = ctxt->state->value;
8864 if (value != NULL)
8865 xmlFree(value);
8866 ctxt->state->value = oldvalue;
8867 ctxt->state->seq = oldseq;
8868 if (ret == 0) {
8869 /*
8870 * flag the attribute as processed
8871 */
8872 ctxt->state->attrs[i] = NULL;
8873 ctxt->state->nbAttrLeft--;
8874 }
8875 } else {
8876 ret = -1;
8877 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008878#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008879 xmlGenericError(xmlGenericErrorContext,
8880 "xmlRelaxNGValidateAttribute(%s): %d\n",
8881 define->name, ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008882#endif
8883 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008884 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8885 tmp = ctxt->state->attrs[i];
8886 if ((tmp != NULL) &&
8887 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
8888 prop = tmp;
8889 break;
8890 }
8891 }
8892 if (prop != NULL) {
8893 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8894 oldvalue = ctxt->state->value;
8895 oldseq = ctxt->state->seq;
8896 ctxt->state->seq = (xmlNodePtr) prop;
8897 ctxt->state->value = value;
8898 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8899 if (ctxt->state->value != NULL)
8900 value = ctxt->state->value;
8901 if (value != NULL)
8902 xmlFree(value);
8903 ctxt->state->value = oldvalue;
8904 ctxt->state->seq = oldseq;
8905 if (ret == 0) {
8906 /*
8907 * flag the attribute as processed
8908 */
8909 ctxt->state->attrs[i] = NULL;
8910 ctxt->state->nbAttrLeft--;
8911 }
8912 } else {
8913 ret = -1;
8914 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008915#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008916 if (define->ns != NULL) {
8917 xmlGenericError(xmlGenericErrorContext,
8918 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8919 define->ns, ret);
8920 } else {
8921 xmlGenericError(xmlGenericErrorContext,
8922 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8923 ret);
8924 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008925#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008926 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008927
8928 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008929}
8930
8931/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008932 * xmlRelaxNGValidateAttributeList:
8933 * @ctxt: a Relax-NG validation context
8934 * @define: the list of definition to verify
8935 *
8936 * Validate the given node against the list of attribute definitions
8937 *
8938 * Returns 0 if the validation succeeded or an error code.
8939 */
8940static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008941xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8942 xmlRelaxNGDefinePtr defines)
8943{
Daniel Veillardce192eb2003-04-16 15:58:05 +00008944 int ret = 0, res;
8945 int needmore = 0;
8946 xmlRelaxNGDefinePtr cur;
8947
8948 cur = defines;
8949 while (cur != NULL) {
8950 if (cur->type == XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008951 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
8952 ret = -1;
8953 } else
8954 needmore = 1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008955 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008956 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008957 if (!needmore)
Daniel Veillard4c004142003-10-07 11:33:24 +00008958 return (ret);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008959 cur = defines;
8960 while (cur != NULL) {
8961 if (cur->type != XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008962 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
8963 res = xmlRelaxNGValidateDefinition(ctxt, cur);
8964 if (res < 0)
8965 ret = -1;
8966 } else {
8967 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8968 return (-1);
8969 }
8970 if (res == -1) /* continues on -2 */
8971 break;
8972 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008973 cur = cur->next;
8974 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008975
8976 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008977}
8978
8979/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008980 * xmlRelaxNGNodeMatchesList:
8981 * @node: the node
8982 * @list: a NULL terminated array of definitions
8983 *
8984 * Check if a node can be matched by one of the definitions
8985 *
8986 * Returns 1 if matches 0 otherwise
8987 */
8988static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008989xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
8990{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008991 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008992 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008993
8994 if ((node == NULL) || (list == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00008995 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008996
8997 cur = list[i++];
8998 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008999 if ((node->type == XML_ELEMENT_NODE) &&
9000 (cur->type == XML_RELAXNG_ELEMENT)) {
9001 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
9002 if (tmp == 1)
9003 return (1);
9004 } else if (((node->type == XML_TEXT_NODE) ||
9005 (node->type == XML_CDATA_SECTION_NODE)) &&
9006 (cur->type == XML_RELAXNG_TEXT)) {
9007 return (1);
9008 }
9009 cur = list[i++];
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009010 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009011 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009012}
9013
9014/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009015 * xmlRelaxNGValidateInterleave:
9016 * @ctxt: a Relax-NG validation context
9017 * @define: the definition to verify
9018 *
9019 * Validate an interleave definition for a node.
9020 *
9021 * Returns 0 if the validation succeeded or an error code.
9022 */
9023static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009024xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
9025 xmlRelaxNGDefinePtr define)
9026{
William M. Brack779af002003-08-01 15:55:39 +00009027 int ret = 0, i, nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009028 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009029 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009030
9031 xmlRelaxNGValidStatePtr oldstate;
9032 xmlRelaxNGPartitionPtr partitions;
9033 xmlRelaxNGInterleaveGroupPtr group = NULL;
9034 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
9035 xmlNodePtr *list = NULL, *lasts = NULL;
9036
9037 if (define->data != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009038 partitions = (xmlRelaxNGPartitionPtr) define->data;
9039 nbgroups = partitions->nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009040 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009041 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
9042 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009043 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009044 /*
9045 * Optimizations for MIXED
9046 */
9047 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00009048 if (define->dflags & IS_MIXED) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009049 ctxt->flags |= FLAGS_MIXED_CONTENT;
9050 if (nbgroups == 2) {
9051 /*
9052 * this is a pure <mixed> case
9053 */
9054 if (ctxt->state != NULL)
9055 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9056 ctxt->state->seq);
9057 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
9058 ret = xmlRelaxNGValidateDefinition(ctxt,
9059 partitions->groups[1]->
9060 rule);
9061 else
9062 ret = xmlRelaxNGValidateDefinition(ctxt,
9063 partitions->groups[0]->
9064 rule);
9065 if (ret == 0) {
9066 if (ctxt->state != NULL)
9067 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9068 ctxt->state->
9069 seq);
9070 }
9071 ctxt->flags = oldflags;
9072 return (ret);
9073 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009074 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009075
9076 /*
9077 * Build arrays to store the first and last node of the chain
9078 * pertaining to each group
9079 */
9080 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9081 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009082 xmlRngVErrMemory(ctxt, "validating\n");
9083 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009084 }
9085 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
9086 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9087 if (lasts == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009088 xmlRngVErrMemory(ctxt, "validating\n");
9089 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009090 }
9091 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
9092
9093 /*
9094 * Walk the sequence of children finding the right group and
9095 * sorting them in sequences.
9096 */
9097 cur = ctxt->state->seq;
9098 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9099 start = cur;
9100 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009101 ctxt->state->seq = cur;
9102 if ((partitions->triage != NULL) &&
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009103 (partitions->flags & IS_DETERMINIST)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009104 void *tmp = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009105
Daniel Veillard4c004142003-10-07 11:33:24 +00009106 if ((cur->type == XML_TEXT_NODE) ||
9107 (cur->type == XML_CDATA_SECTION_NODE)) {
9108 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
9109 NULL);
9110 } else if (cur->type == XML_ELEMENT_NODE) {
9111 if (cur->ns != NULL) {
9112 tmp = xmlHashLookup2(partitions->triage, cur->name,
9113 cur->ns->href);
9114 if (tmp == NULL)
9115 tmp = xmlHashLookup2(partitions->triage,
9116 BAD_CAST "#any",
9117 cur->ns->href);
9118 } else
9119 tmp =
9120 xmlHashLookup2(partitions->triage, cur->name,
9121 NULL);
9122 if (tmp == NULL)
9123 tmp =
9124 xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9125 NULL);
9126 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009127
Daniel Veillard4c004142003-10-07 11:33:24 +00009128 if (tmp == NULL) {
9129 i = nbgroups;
9130 } else {
9131 i = ((long) tmp) - 1;
9132 if (partitions->flags & IS_NEEDCHECK) {
9133 group = partitions->groups[i];
9134 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9135 i = nbgroups;
9136 }
9137 }
9138 } else {
9139 for (i = 0; i < nbgroups; i++) {
9140 group = partitions->groups[i];
9141 if (group == NULL)
9142 continue;
9143 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9144 break;
9145 }
9146 }
9147 /*
9148 * We break as soon as an element not matched is found
9149 */
9150 if (i >= nbgroups) {
9151 break;
9152 }
9153 if (lasts[i] != NULL) {
9154 lasts[i]->next = cur;
9155 lasts[i] = cur;
9156 } else {
9157 list[i] = cur;
9158 lasts[i] = cur;
9159 }
9160 if (cur->next != NULL)
9161 lastchg = cur->next;
9162 else
9163 lastchg = cur;
9164 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009165 }
9166 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009167 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9168 ret = -1;
9169 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009170 }
9171 lastelem = cur;
9172 oldstate = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009173 for (i = 0; i < nbgroups; i++) {
9174 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9175 group = partitions->groups[i];
9176 if (lasts[i] != NULL) {
9177 last = lasts[i]->next;
9178 lasts[i]->next = NULL;
9179 }
9180 ctxt->state->seq = list[i];
9181 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9182 if (ret != 0)
9183 break;
9184 if (ctxt->state != NULL) {
9185 cur = ctxt->state->seq;
9186 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9187 xmlRelaxNGFreeValidState(ctxt, oldstate);
9188 oldstate = ctxt->state;
9189 ctxt->state = NULL;
9190 if (cur != NULL) {
9191 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9192 ret = -1;
9193 ctxt->state = oldstate;
9194 goto done;
9195 }
9196 } else if (ctxt->states != NULL) {
9197 int j;
9198 int found = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009199
Daniel Veillard4c004142003-10-07 11:33:24 +00009200 for (j = 0; j < ctxt->states->nbState; j++) {
9201 cur = ctxt->states->tabState[j]->seq;
9202 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9203 if (cur == NULL) {
9204 found = 1;
9205 break;
9206 }
9207 }
9208 if (ctxt->states->nbState > 0) {
9209 xmlRelaxNGFreeValidState(ctxt, oldstate);
9210 oldstate =
9211 ctxt->states->tabState[ctxt->states->nbState - 1];
9212 }
9213 for (j = 0; j < ctxt->states->nbState - 1; j++) {
9214 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
9215 }
9216 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9217 ctxt->states = NULL;
9218 if (found == 0) {
9219 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9220 ret = -1;
9221 ctxt->state = oldstate;
9222 goto done;
9223 }
9224 } else {
9225 ret = -1;
9226 break;
9227 }
9228 if (lasts[i] != NULL) {
9229 lasts[i]->next = last;
9230 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009231 }
9232 if (ctxt->state != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009233 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009234 ctxt->state = oldstate;
9235 ctxt->state->seq = lastelem;
9236 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009237 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9238 ret = -1;
9239 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009240 }
9241
Daniel Veillard4c004142003-10-07 11:33:24 +00009242 done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009243 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009244 /*
9245 * builds the next links chain from the prev one
9246 */
9247 cur = lastchg;
9248 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009249 if ((cur == start) || (cur->prev == NULL))
9250 break;
9251 cur->prev->next = cur;
9252 cur = cur->prev;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009253 }
9254 if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009255 if (ctxt->errNr > errNr)
9256 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009257 }
9258
9259 xmlFree(list);
9260 xmlFree(lasts);
Daniel Veillard4c004142003-10-07 11:33:24 +00009261 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009262}
9263
9264/**
9265 * xmlRelaxNGValidateDefinitionList:
9266 * @ctxt: a Relax-NG validation context
9267 * @define: the list of definition to verify
9268 *
9269 * Validate the given node content against the (list) of definitions
9270 *
9271 * Returns 0 if the validation succeeded or an error code.
9272 */
9273static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009274xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9275 xmlRelaxNGDefinePtr defines)
9276{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009277 int ret = 0, res;
9278
9279
Daniel Veillard952379b2003-03-17 15:37:12 +00009280 if (defines == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009281 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
9282 BAD_CAST "NULL definition list");
9283 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00009284 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009285 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009286 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9287 res = xmlRelaxNGValidateDefinition(ctxt, defines);
9288 if (res < 0)
9289 ret = -1;
9290 } else {
9291 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9292 return (-1);
9293 }
9294 if (res == -1) /* continues on -2 */
9295 break;
9296 defines = defines->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009297 }
9298
Daniel Veillard4c004142003-10-07 11:33:24 +00009299 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009300}
9301
9302/**
9303 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00009304 * @ctxt: a Relax-NG validation context
9305 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00009306 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00009307 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009308 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00009309 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009310 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00009311 */
9312static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009313xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9314 xmlRelaxNGDefinePtr define, xmlNodePtr elem)
9315{
Daniel Veillard580ced82003-03-21 21:22:48 +00009316 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00009317
Daniel Veillardfd573f12003-03-16 17:52:32 +00009318 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009319 if (!xmlStrEqual(elem->name, define->name)) {
9320 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9321 return (0);
9322 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009323 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009324 if ((define->ns != NULL) && (define->ns[0] != 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009325 if (elem->ns == NULL) {
9326 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
9327 return (0);
9328 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9329 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9330 elem->name, define->ns);
9331 return (0);
9332 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009333 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00009334 (define->name == NULL)) {
9335 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
9336 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009337 } else if ((elem->ns != NULL) && (define->name != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009338 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
9339 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009340 }
9341
9342 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009343 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009344
9345 define = define->nameClass;
9346 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009347 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009348
Daniel Veillard4c004142003-10-07 11:33:24 +00009349 if (ctxt != NULL) {
9350 oldflags = ctxt->flags;
9351 ctxt->flags |= FLAGS_IGNORABLE;
9352 }
9353
9354 list = define->content;
9355 while (list != NULL) {
9356 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9357 if (ret == 1) {
9358 if (ctxt != NULL)
9359 ctxt->flags = oldflags;
9360 return (0);
9361 }
9362 if (ret < 0) {
9363 if (ctxt != NULL)
9364 ctxt->flags = oldflags;
9365 return (ret);
9366 }
9367 list = list->next;
9368 }
9369 ret = 1;
9370 if (ctxt != NULL) {
9371 ctxt->flags = oldflags;
9372 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009373 } else if (define->type == XML_RELAXNG_CHOICE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009374 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009375
Daniel Veillard4c004142003-10-07 11:33:24 +00009376 if (ctxt != NULL) {
9377 oldflags = ctxt->flags;
9378 ctxt->flags |= FLAGS_IGNORABLE;
9379 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009380
Daniel Veillard4c004142003-10-07 11:33:24 +00009381 list = define->nameClass;
9382 while (list != NULL) {
9383 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9384 if (ret == 1) {
9385 if (ctxt != NULL)
9386 ctxt->flags = oldflags;
9387 return (1);
9388 }
9389 if (ret < 0) {
9390 if (ctxt != NULL)
9391 ctxt->flags = oldflags;
9392 return (ret);
9393 }
9394 list = list->next;
9395 }
9396 if (ctxt != NULL) {
9397 if (ret != 0) {
9398 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9399 xmlRelaxNGDumpValidError(ctxt);
9400 } else {
9401 if (ctxt->errNr > 0)
9402 xmlRelaxNGPopErrors(ctxt, 0);
9403 }
9404 }
9405 ret = 0;
9406 if (ctxt != NULL) {
9407 ctxt->flags = oldflags;
9408 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009409 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009410 TODO ret = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009411 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009412 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009413}
9414
9415/**
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009416 * xmlRelaxNGBestState:
9417 * @ctxt: a Relax-NG validation context
9418 *
9419 * Find the "best" state in the ctxt->states list of states to report
9420 * errors about. I.e. a state with no element left in the child list
9421 * or the one with the less attributes left.
9422 * This is called only if a falidation error was detected
9423 *
9424 * Returns the index of the "best" state or -1 in case of error
9425 */
9426static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009427xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
9428{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009429 xmlRelaxNGValidStatePtr state;
9430 int i, tmp;
9431 int best = -1;
9432 int value = 1000000;
9433
9434 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9435 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009436 return (-1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009437
Daniel Veillard4c004142003-10-07 11:33:24 +00009438 for (i = 0; i < ctxt->states->nbState; i++) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009439 state = ctxt->states->tabState[i];
Daniel Veillard4c004142003-10-07 11:33:24 +00009440 if (state == NULL)
9441 continue;
9442 if (state->seq != NULL) {
9443 if ((best == -1) || (value > 100000)) {
9444 value = 100000;
9445 best = i;
9446 }
9447 } else {
9448 tmp = state->nbAttrLeft;
9449 if ((best == -1) || (value > tmp)) {
9450 value = tmp;
9451 best = i;
9452 }
9453 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009454 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009455 return (best);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009456}
9457
9458/**
9459 * xmlRelaxNGLogBestError:
9460 * @ctxt: a Relax-NG validation context
9461 *
9462 * Find the "best" state in the ctxt->states list of states to report
9463 * errors about and log it.
9464 */
9465static void
Daniel Veillard4c004142003-10-07 11:33:24 +00009466xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
9467{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009468 int best;
9469
9470 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9471 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009472 return;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009473
9474 best = xmlRelaxNGBestState(ctxt);
9475 if ((best >= 0) && (best < ctxt->states->nbState)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009476 ctxt->state = ctxt->states->tabState[best];
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009477
Daniel Veillard4c004142003-10-07 11:33:24 +00009478 xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009479 }
9480}
9481
9482/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009483 * xmlRelaxNGValidateElementEnd:
9484 * @ctxt: a Relax-NG validation context
William M. Brack272693c2003-11-14 16:20:34 +00009485 * @dolog: indicate that error logging should be done
Daniel Veillardfd573f12003-03-16 17:52:32 +00009486 *
9487 * Validate the end of the element, implements check that
9488 * there is nothing left not consumed in the element content
9489 * or in the attribute list.
9490 *
9491 * Returns 0 if the validation succeeded or an error code.
9492 */
9493static int
William M. Brack272693c2003-11-14 16:20:34 +00009494xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
Daniel Veillard4c004142003-10-07 11:33:24 +00009495{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009496 int i;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009497 xmlRelaxNGValidStatePtr state;
9498
9499 state = ctxt->state;
9500 if (state->seq != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009501 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9502 if (state->seq != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009503 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009504 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9505 state->node->name, state->seq->name);
9506 }
9507 return (-1);
9508 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009509 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009510 for (i = 0; i < state->nbAttrs; i++) {
9511 if (state->attrs[i] != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009512 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009513 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9514 state->attrs[i]->name, state->node->name);
9515 }
9516 return (-1 - i);
9517 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009518 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009519 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009520}
9521
9522/**
9523 * xmlRelaxNGValidateState:
9524 * @ctxt: a Relax-NG validation context
9525 * @define: the definition to verify
9526 *
9527 * Validate the current state against the definition
9528 *
9529 * Returns 0 if the validation succeeded or an error code.
9530 */
9531static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009532xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9533 xmlRelaxNGDefinePtr define)
9534{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009535 xmlNodePtr node;
9536 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009537 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009538
9539 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009540 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9541 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009542 }
9543
9544 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009545 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009546 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009547 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009548 }
9549#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009550 for (i = 0; i < ctxt->depth; i++)
9551 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009552 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009553 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009554 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009555 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009556 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009557 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009558 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009559 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009560#endif
9561 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009562 switch (define->type) {
9563 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009564 node = xmlRelaxNGSkipIgnored(ctxt, node);
9565 ret = 0;
9566 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009567 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009568 ret = -1;
9569 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009570 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009571 while ((node != NULL) &&
9572 ((node->type == XML_TEXT_NODE) ||
9573 (node->type == XML_COMMENT_NODE) ||
9574 (node->type == XML_PI_NODE) ||
9575 (node->type == XML_CDATA_SECTION_NODE)))
9576 node = node->next;
9577 ctxt->state->seq = node;
9578 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009579 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009580 errNr = ctxt->errNr;
9581 node = xmlRelaxNGSkipIgnored(ctxt, node);
9582 if (node == NULL) {
9583 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9584 ret = -1;
9585 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9586 xmlRelaxNGDumpValidError(ctxt);
9587 break;
9588 }
9589 if (node->type != XML_ELEMENT_NODE) {
9590 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9591 ret = -1;
9592 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9593 xmlRelaxNGDumpValidError(ctxt);
9594 break;
9595 }
9596 /*
9597 * This node was already validated successfully against
9598 * this definition.
9599 */
Daniel Veillard807daf82004-02-22 22:13:27 +00009600 if (node->psvi == define) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009601 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9602 if (ctxt->errNr > errNr)
9603 xmlRelaxNGPopErrors(ctxt, errNr);
9604 if (ctxt->errNr != 0) {
9605 while ((ctxt->err != NULL) &&
9606 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9607 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9608 ||
9609 ((ctxt->err->err ==
9610 XML_RELAXNG_ERR_ELEMEXTRANS)
9611 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9612 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9613 || (ctxt->err->err ==
9614 XML_RELAXNG_ERR_NOTELEM)))
9615 xmlRelaxNGValidErrorPop(ctxt);
9616 }
9617 break;
9618 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009619
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009620 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9621 if (ret <= 0) {
9622 ret = -1;
9623 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9624 xmlRelaxNGDumpValidError(ctxt);
9625 break;
9626 }
9627 ret = 0;
9628 if (ctxt->errNr != 0) {
9629 if (ctxt->errNr > errNr)
9630 xmlRelaxNGPopErrors(ctxt, errNr);
9631 while ((ctxt->err != NULL) &&
9632 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9633 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9634 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9635 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9636 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9637 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9638 xmlRelaxNGValidErrorPop(ctxt);
9639 }
9640 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009641
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009642 oldflags = ctxt->flags;
9643 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9644 ctxt->flags -= FLAGS_MIXED_CONTENT;
9645 }
9646 state = xmlRelaxNGNewValidState(ctxt, node);
9647 if (state == NULL) {
9648 ret = -1;
9649 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9650 xmlRelaxNGDumpValidError(ctxt);
9651 break;
9652 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009653
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009654 oldstate = ctxt->state;
9655 ctxt->state = state;
9656 if (define->attrs != NULL) {
9657 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9658 if (tmp != 0) {
9659 ret = -1;
9660 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9661 }
9662 }
9663 if (define->contModel != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009664 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9665 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9666 xmlNodePtr nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009667
Daniel Veillard4c004142003-10-07 11:33:24 +00009668 nstate = xmlRelaxNGNewValidState(ctxt, node);
9669 ctxt->state = nstate;
9670 ctxt->states = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009671
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009672 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9673 define->contModel,
9674 ctxt->state->seq);
Daniel Veillard4c004142003-10-07 11:33:24 +00009675 nseq = ctxt->state->seq;
9676 ctxt->state = tmpstate;
9677 ctxt->states = tmpstates;
9678 xmlRelaxNGFreeValidState(ctxt, nstate);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009679
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009680#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00009681 xmlGenericError(xmlGenericErrorContext,
9682 "Validating content of '%s' : %d\n",
9683 define->name, tmp);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009684#endif
Daniel Veillardce192eb2003-04-16 15:58:05 +00009685 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00009686 ret = -1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009687
9688 if (ctxt->states != NULL) {
9689 tmp = -1;
9690
Daniel Veillardce192eb2003-04-16 15:58:05 +00009691 for (i = 0; i < ctxt->states->nbState; i++) {
9692 state = ctxt->states->tabState[i];
9693 ctxt->state = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009694 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009695
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009696 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00009697 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009698 break;
9699 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009700 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009701 if (tmp != 0) {
9702 /*
9703 * validation error, log the message for the "best" one
9704 */
9705 ctxt->flags |= FLAGS_IGNORABLE;
9706 xmlRelaxNGLogBestError(ctxt);
9707 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009708 for (i = 0; i < ctxt->states->nbState; i++) {
9709 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009710 ctxt->states->
9711 tabState[i]);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009712 }
9713 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9714 ctxt->flags = oldflags;
9715 ctxt->states = NULL;
9716 if ((ret == 0) && (tmp == -1))
9717 ret = -1;
9718 } else {
9719 state = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009720 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009721 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009722 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009723 xmlRelaxNGFreeValidState(ctxt, state);
9724 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009725 } else {
9726 if (define->content != NULL) {
9727 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009728 define->
9729 content);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009730 if (tmp != 0) {
9731 ret = -1;
9732 if (ctxt->state == NULL) {
9733 ctxt->state = oldstate;
9734 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9735 node->name);
9736 ctxt->state = NULL;
9737 } else {
9738 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9739 node->name);
9740 }
9741
9742 }
9743 }
9744 if (ctxt->states != NULL) {
9745 tmp = -1;
9746
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009747 for (i = 0; i < ctxt->states->nbState; i++) {
9748 state = ctxt->states->tabState[i];
9749 ctxt->state = state;
9750
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009751 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009752 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009753 break;
9754 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009755 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009756 if (tmp != 0) {
9757 /*
9758 * validation error, log the message for the "best" one
9759 */
9760 ctxt->flags |= FLAGS_IGNORABLE;
9761 xmlRelaxNGLogBestError(ctxt);
9762 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009763 for (i = 0; i < ctxt->states->nbState; i++) {
9764 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009765 ctxt->states->
9766 tabState[i]);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009767 }
9768 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9769 ctxt->flags = oldflags;
9770 ctxt->states = NULL;
9771 if ((ret == 0) && (tmp == -1))
9772 ret = -1;
9773 } else {
9774 state = ctxt->state;
9775 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009776 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009777 xmlRelaxNGFreeValidState(ctxt, state);
9778 }
9779 }
9780 if (ret == 0) {
Daniel Veillard807daf82004-02-22 22:13:27 +00009781 node->psvi = define;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009782 }
9783 ctxt->flags = oldflags;
9784 ctxt->state = oldstate;
9785 if (oldstate != NULL)
9786 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9787 if (ret != 0) {
9788 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9789 xmlRelaxNGDumpValidError(ctxt);
9790 ret = 0;
9791 } else {
9792 ret = -2;
9793 }
9794 } else {
9795 if (ctxt->errNr > errNr)
9796 xmlRelaxNGPopErrors(ctxt, errNr);
9797 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009798
9799#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009800 xmlGenericError(xmlGenericErrorContext,
9801 "xmlRelaxNGValidateDefinition(): validated %s : %d",
9802 node->name, ret);
9803 if (oldstate == NULL)
9804 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9805 else if (oldstate->seq == NULL)
9806 xmlGenericError(xmlGenericErrorContext, ": done\n");
9807 else if (oldstate->seq->type == XML_ELEMENT_NODE)
9808 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9809 oldstate->seq->name);
9810 else
9811 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9812 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009813#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009814 break;
9815 case XML_RELAXNG_OPTIONAL:{
9816 errNr = ctxt->errNr;
9817 oldflags = ctxt->flags;
9818 ctxt->flags |= FLAGS_IGNORABLE;
9819 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9820 ret =
9821 xmlRelaxNGValidateDefinitionList(ctxt,
9822 define->content);
9823 if (ret != 0) {
9824 if (ctxt->state != NULL)
9825 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9826 ctxt->state = oldstate;
9827 ctxt->flags = oldflags;
9828 ret = 0;
9829 if (ctxt->errNr > errNr)
9830 xmlRelaxNGPopErrors(ctxt, errNr);
9831 break;
9832 }
9833 if (ctxt->states != NULL) {
9834 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9835 } else {
9836 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9837 if (ctxt->states == NULL) {
9838 xmlRelaxNGFreeValidState(ctxt, oldstate);
9839 ctxt->flags = oldflags;
9840 ret = -1;
9841 if (ctxt->errNr > errNr)
9842 xmlRelaxNGPopErrors(ctxt, errNr);
9843 break;
9844 }
9845 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9846 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9847 ctxt->state = NULL;
9848 }
9849 ctxt->flags = oldflags;
9850 ret = 0;
9851 if (ctxt->errNr > errNr)
9852 xmlRelaxNGPopErrors(ctxt, errNr);
9853 break;
9854 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009855 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009856 errNr = ctxt->errNr;
9857 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9858 if (ret != 0) {
9859 break;
9860 }
9861 if (ctxt->errNr > errNr)
9862 xmlRelaxNGPopErrors(ctxt, errNr);
9863 /* no break on purpose */
9864 case XML_RELAXNG_ZEROORMORE:{
9865 int progress;
9866 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9867 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009868
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009869 errNr = ctxt->errNr;
9870 res = xmlRelaxNGNewStates(ctxt, 1);
9871 if (res == NULL) {
9872 ret = -1;
9873 break;
9874 }
9875 /*
9876 * All the input states are also exit states
9877 */
9878 if (ctxt->state != NULL) {
9879 xmlRelaxNGAddStates(ctxt, res,
9880 xmlRelaxNGCopyValidState(ctxt,
9881 ctxt->
9882 state));
9883 } else {
9884 for (j = 0; j < ctxt->states->nbState; j++) {
9885 xmlRelaxNGAddStates(ctxt, res,
9886 xmlRelaxNGCopyValidState(ctxt,
9887 ctxt->
9888 states->
9889 tabState
9890 [j]));
9891 }
9892 }
9893 oldflags = ctxt->flags;
9894 ctxt->flags |= FLAGS_IGNORABLE;
9895 do {
9896 progress = 0;
9897 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009898
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009899 if (ctxt->states != NULL) {
9900 states = ctxt->states;
9901 for (i = 0; i < states->nbState; i++) {
9902 ctxt->state = states->tabState[i];
9903 ctxt->states = NULL;
9904 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9905 define->
9906 content);
9907 if (ret == 0) {
9908 if (ctxt->state != NULL) {
9909 tmp = xmlRelaxNGAddStates(ctxt, res,
9910 ctxt->state);
9911 ctxt->state = NULL;
9912 if (tmp == 1)
9913 progress = 1;
9914 } else if (ctxt->states != NULL) {
9915 for (j = 0; j < ctxt->states->nbState;
9916 j++) {
9917 tmp =
9918 xmlRelaxNGAddStates(ctxt, res,
9919 ctxt->
9920 states->
9921 tabState
9922 [j]);
9923 if (tmp == 1)
9924 progress = 1;
9925 }
9926 xmlRelaxNGFreeStates(ctxt,
9927 ctxt->states);
9928 ctxt->states = NULL;
9929 }
9930 } else {
9931 if (ctxt->state != NULL) {
9932 xmlRelaxNGFreeValidState(ctxt,
9933 ctxt->state);
9934 ctxt->state = NULL;
9935 }
9936 }
9937 }
9938 } else {
9939 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9940 define->
9941 content);
9942 if (ret != 0) {
9943 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9944 ctxt->state = NULL;
9945 } else {
9946 base = res->nbState;
9947 if (ctxt->state != NULL) {
9948 tmp = xmlRelaxNGAddStates(ctxt, res,
9949 ctxt->state);
9950 ctxt->state = NULL;
9951 if (tmp == 1)
9952 progress = 1;
9953 } else if (ctxt->states != NULL) {
9954 for (j = 0; j < ctxt->states->nbState; j++) {
9955 tmp = xmlRelaxNGAddStates(ctxt, res,
9956 ctxt->
9957 states->
9958 tabState[j]);
9959 if (tmp == 1)
9960 progress = 1;
9961 }
9962 if (states == NULL) {
9963 states = ctxt->states;
9964 } else {
9965 xmlRelaxNGFreeStates(ctxt,
9966 ctxt->states);
9967 }
9968 ctxt->states = NULL;
9969 }
9970 }
9971 }
9972 if (progress) {
9973 /*
9974 * Collect all the new nodes added at that step
9975 * and make them the new node set
9976 */
9977 if (res->nbState - base == 1) {
9978 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
9979 res->
9980 tabState
9981 [base]);
9982 } else {
9983 if (states == NULL) {
9984 xmlRelaxNGNewStates(ctxt,
9985 res->nbState - base);
9986 }
9987 states->nbState = 0;
9988 for (i = base; i < res->nbState; i++)
9989 xmlRelaxNGAddStates(ctxt, states,
9990 xmlRelaxNGCopyValidState
9991 (ctxt,
9992 res->tabState[i]));
9993 ctxt->states = states;
9994 }
9995 }
9996 } while (progress == 1);
9997 if (states != NULL) {
9998 xmlRelaxNGFreeStates(ctxt, states);
9999 }
10000 ctxt->states = res;
10001 ctxt->flags = oldflags;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010002#if 0
10003 /*
Daniel Veillard4c004142003-10-07 11:33:24 +000010004 * errors may have to be propagated back...
10005 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010006 if (ctxt->errNr > errNr)
10007 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010008#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010009 ret = 0;
10010 break;
10011 }
10012 case XML_RELAXNG_CHOICE:{
10013 xmlRelaxNGDefinePtr list = NULL;
10014 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010015
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010016 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010017
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010018 errNr = ctxt->errNr;
10019 if ((define->dflags & IS_TRIABLE)
10020 && (define->data != NULL)) {
10021 xmlHashTablePtr triage =
10022 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +000010023
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010024 /*
10025 * Something we can optimize cleanly there is only one
10026 * possble branch out !
10027 */
10028 if (node == NULL) {
10029 ret = -1;
10030 break;
10031 }
10032 if ((node->type == XML_TEXT_NODE) ||
10033 (node->type == XML_CDATA_SECTION_NODE)) {
10034 list =
10035 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10036 } else if (node->type == XML_ELEMENT_NODE) {
10037 if (node->ns != NULL) {
10038 list = xmlHashLookup2(triage, node->name,
10039 node->ns->href);
10040 if (list == NULL)
10041 list =
10042 xmlHashLookup2(triage, BAD_CAST "#any",
10043 node->ns->href);
10044 } else
10045 list =
10046 xmlHashLookup2(triage, node->name, NULL);
10047 if (list == NULL)
10048 list =
10049 xmlHashLookup2(triage, BAD_CAST "#any",
10050 NULL);
10051 }
10052 if (list == NULL) {
10053 ret = -1;
William M. Brack2f076062004-03-21 11:21:14 +000010054 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010055 break;
10056 }
10057 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10058 if (ret == 0) {
10059 }
10060 break;
10061 }
Daniel Veillarde063f482003-03-21 16:53:17 +000010062
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010063 list = define->content;
10064 oldflags = ctxt->flags;
10065 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010066
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010067 while (list != NULL) {
10068 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10069 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10070 if (ret == 0) {
10071 if (states == NULL) {
10072 states = xmlRelaxNGNewStates(ctxt, 1);
10073 }
10074 if (ctxt->state != NULL) {
10075 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10076 } else if (ctxt->states != NULL) {
10077 for (i = 0; i < ctxt->states->nbState; i++) {
10078 xmlRelaxNGAddStates(ctxt, states,
10079 ctxt->states->
10080 tabState[i]);
10081 }
10082 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10083 ctxt->states = NULL;
10084 }
10085 } else {
10086 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10087 }
10088 ctxt->state = oldstate;
10089 list = list->next;
10090 }
10091 if (states != NULL) {
10092 xmlRelaxNGFreeValidState(ctxt, oldstate);
10093 ctxt->states = states;
10094 ctxt->state = NULL;
10095 ret = 0;
10096 } else {
10097 ctxt->states = NULL;
10098 }
10099 ctxt->flags = oldflags;
10100 if (ret != 0) {
10101 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10102 xmlRelaxNGDumpValidError(ctxt);
10103 }
10104 } else {
10105 if (ctxt->errNr > errNr)
10106 xmlRelaxNGPopErrors(ctxt, errNr);
10107 }
10108 break;
10109 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010110 case XML_RELAXNG_DEF:
10111 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010112 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10113 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010114 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010115 ret = xmlRelaxNGValidateInterleave(ctxt, define);
10116 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010117 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010118 ret = xmlRelaxNGValidateAttribute(ctxt, define);
10119 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +000010120 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010121 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +000010122 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010123 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +000010124 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010125 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10126 break;
10127 case XML_RELAXNG_DATATYPE:{
10128 xmlNodePtr child;
10129 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010130
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010131 child = node;
10132 while (child != NULL) {
10133 if (child->type == XML_ELEMENT_NODE) {
10134 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10135 node->parent->name);
10136 ret = -1;
10137 break;
10138 } else if ((child->type == XML_TEXT_NODE) ||
10139 (child->type == XML_CDATA_SECTION_NODE)) {
10140 content = xmlStrcat(content, child->content);
10141 }
10142 /* TODO: handle entities ... */
10143 child = child->next;
10144 }
10145 if (ret == -1) {
10146 if (content != NULL)
10147 xmlFree(content);
10148 break;
10149 }
10150 if (content == NULL) {
10151 content = xmlStrdup(BAD_CAST "");
10152 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010153 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010154 ret = -1;
10155 break;
10156 }
10157 }
10158 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10159 ctxt->state->seq);
10160 if (ret == -1) {
10161 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10162 } else if (ret == 0) {
10163 ctxt->state->seq = NULL;
10164 }
10165 if (content != NULL)
10166 xmlFree(content);
10167 break;
10168 }
10169 case XML_RELAXNG_VALUE:{
10170 xmlChar *content = NULL;
10171 xmlChar *oldvalue;
10172 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010173
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010174 child = node;
10175 while (child != NULL) {
10176 if (child->type == XML_ELEMENT_NODE) {
10177 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10178 node->parent->name);
10179 ret = -1;
10180 break;
10181 } else if ((child->type == XML_TEXT_NODE) ||
10182 (child->type == XML_CDATA_SECTION_NODE)) {
10183 content = xmlStrcat(content, child->content);
10184 }
10185 /* TODO: handle entities ... */
10186 child = child->next;
10187 }
10188 if (ret == -1) {
10189 if (content != NULL)
10190 xmlFree(content);
10191 break;
10192 }
10193 if (content == NULL) {
10194 content = xmlStrdup(BAD_CAST "");
10195 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010196 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010197 ret = -1;
10198 break;
10199 }
10200 }
10201 oldvalue = ctxt->state->value;
10202 ctxt->state->value = content;
10203 ret = xmlRelaxNGValidateValue(ctxt, define);
10204 ctxt->state->value = oldvalue;
10205 if (ret == -1) {
10206 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10207 } else if (ret == 0) {
10208 ctxt->state->seq = NULL;
10209 }
10210 if (content != NULL)
10211 xmlFree(content);
10212 break;
10213 }
10214 case XML_RELAXNG_LIST:{
10215 xmlChar *content;
10216 xmlNodePtr child;
10217 xmlChar *oldvalue, *oldendvalue;
10218 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010219
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010220 /*
10221 * Make sure it's only text nodes
10222 */
10223
10224 content = NULL;
10225 child = node;
10226 while (child != NULL) {
10227 if (child->type == XML_ELEMENT_NODE) {
10228 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10229 node->parent->name);
10230 ret = -1;
10231 break;
10232 } else if ((child->type == XML_TEXT_NODE) ||
10233 (child->type == XML_CDATA_SECTION_NODE)) {
10234 content = xmlStrcat(content, child->content);
10235 }
10236 /* TODO: handle entities ... */
10237 child = child->next;
10238 }
10239 if (ret == -1) {
10240 if (content != NULL)
10241 xmlFree(content);
10242 break;
10243 }
10244 if (content == NULL) {
10245 content = xmlStrdup(BAD_CAST "");
10246 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010247 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010248 ret = -1;
10249 break;
10250 }
10251 }
10252 len = xmlStrlen(content);
10253 oldvalue = ctxt->state->value;
10254 oldendvalue = ctxt->state->endvalue;
10255 ctxt->state->value = content;
10256 ctxt->state->endvalue = content + len;
10257 ret = xmlRelaxNGValidateValue(ctxt, define);
10258 ctxt->state->value = oldvalue;
10259 ctxt->state->endvalue = oldendvalue;
10260 if (ret == -1) {
10261 VALID_ERR(XML_RELAXNG_ERR_LIST);
10262 } else if ((ret == 0) && (node != NULL)) {
10263 ctxt->state->seq = node->next;
10264 }
10265 if (content != NULL)
10266 xmlFree(content);
10267 break;
10268 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010269 case XML_RELAXNG_EXCEPT:
10270 case XML_RELAXNG_PARAM:
10271 TODO ret = -1;
10272 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010273 }
10274 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010275#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010276 for (i = 0; i < ctxt->depth; i++)
10277 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010278 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010279 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +000010280 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010281 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010282 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010283 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010284 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010285 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010286#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010287 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010288}
10289
10290/**
Daniel Veillardfd573f12003-03-16 17:52:32 +000010291 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010292 * @ctxt: a Relax-NG validation context
10293 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010294 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010295 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010296 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010297 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010298 */
10299static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010300xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10301 xmlRelaxNGDefinePtr define)
10302{
Daniel Veillardfd573f12003-03-16 17:52:32 +000010303 xmlRelaxNGStatesPtr states, res;
10304 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010305
Daniel Veillardfd573f12003-03-16 17:52:32 +000010306 /*
10307 * We should NOT have both ctxt->state and ctxt->states
10308 */
10309 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010310 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10311 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010312 }
10313
10314 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010315 if (ctxt->states != NULL) {
10316 ctxt->state = ctxt->states->tabState[0];
10317 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10318 ctxt->states = NULL;
10319 }
10320 ret = xmlRelaxNGValidateState(ctxt, define);
10321 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10322 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10323 ctxt->state = NULL;
10324 }
10325 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10326 ctxt->state = ctxt->states->tabState[0];
10327 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10328 ctxt->states = NULL;
10329 }
10330 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010331 }
10332
10333 states = ctxt->states;
10334 ctxt->states = NULL;
10335 res = NULL;
10336 j = 0;
10337 oldflags = ctxt->flags;
10338 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +000010339 for (i = 0; i < states->nbState; i++) {
10340 ctxt->state = states->tabState[i];
10341 ctxt->states = NULL;
10342 ret = xmlRelaxNGValidateState(ctxt, define);
10343 /*
10344 * We should NOT have both ctxt->state and ctxt->states
10345 */
10346 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10347 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10348 ctxt->state = NULL;
10349 }
10350 if (ret == 0) {
10351 if (ctxt->states == NULL) {
10352 if (res != NULL) {
10353 /* add the state to the container */
10354 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10355 ctxt->state = NULL;
10356 } else {
10357 /* add the state directly in states */
10358 states->tabState[j++] = ctxt->state;
10359 ctxt->state = NULL;
10360 }
10361 } else {
10362 if (res == NULL) {
10363 /* make it the new container and copy other results */
10364 res = ctxt->states;
10365 ctxt->states = NULL;
10366 for (k = 0; k < j; k++)
10367 xmlRelaxNGAddStates(ctxt, res,
10368 states->tabState[k]);
10369 } else {
10370 /* add all the new results to res and reff the container */
10371 for (k = 0; k < ctxt->states->nbState; k++)
10372 xmlRelaxNGAddStates(ctxt, res,
10373 ctxt->states->tabState[k]);
10374 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10375 ctxt->states = NULL;
10376 }
10377 }
10378 } else {
10379 if (ctxt->state != NULL) {
10380 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10381 ctxt->state = NULL;
10382 } else if (ctxt->states != NULL) {
10383 for (k = 0; k < ctxt->states->nbState; k++)
10384 xmlRelaxNGFreeValidState(ctxt,
10385 ctxt->states->tabState[k]);
10386 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10387 ctxt->states = NULL;
10388 }
10389 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010390 }
10391 ctxt->flags = oldflags;
10392 if (res != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010393 xmlRelaxNGFreeStates(ctxt, states);
10394 ctxt->states = res;
10395 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010396 } else if (j > 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010397 states->nbState = j;
10398 ctxt->states = states;
10399 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010400 } else if (j == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010401 ctxt->state = states->tabState[0];
10402 xmlRelaxNGFreeStates(ctxt, states);
10403 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010404 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +000010405 ret = -1;
10406 xmlRelaxNGFreeStates(ctxt, states);
10407 if (ctxt->states != NULL) {
10408 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10409 ctxt->states = NULL;
10410 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010411 }
10412 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010413 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10414 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010415 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010416 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010417}
10418
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010419/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010420 * xmlRelaxNGValidateDocument:
10421 * @ctxt: a Relax-NG validation context
10422 * @doc: the document
10423 *
10424 * Validate the given document
10425 *
10426 * Returns 0 if the validation succeeded or an error code.
10427 */
10428static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010429xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10430{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010431 int ret;
10432 xmlRelaxNGPtr schema;
10433 xmlRelaxNGGrammarPtr grammar;
10434 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010435 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010436
10437 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010438 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010439
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010440 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010441 schema = ctxt->schema;
10442 grammar = schema->topgrammar;
10443 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010444 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10445 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010446 }
10447 state = xmlRelaxNGNewValidState(ctxt, NULL);
10448 ctxt->state = state;
10449 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010450 if ((ctxt->state != NULL) && (state->seq != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010451 state = ctxt->state;
10452 node = state->seq;
10453 node = xmlRelaxNGSkipIgnored(ctxt, node);
10454 if (node != NULL) {
10455 if (ret != -1) {
10456 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10457 ret = -1;
10458 }
10459 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010460 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010461 int i;
10462 int tmp = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010463
Daniel Veillard4c004142003-10-07 11:33:24 +000010464 for (i = 0; i < ctxt->states->nbState; i++) {
10465 state = ctxt->states->tabState[i];
10466 node = state->seq;
10467 node = xmlRelaxNGSkipIgnored(ctxt, node);
10468 if (node == NULL)
10469 tmp = 0;
10470 xmlRelaxNGFreeValidState(ctxt, state);
10471 }
10472 if (tmp == -1) {
10473 if (ret != -1) {
10474 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10475 ret = -1;
10476 }
10477 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010478 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010479 if (ctxt->state != NULL) {
10480 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillard4c004142003-10-07 11:33:24 +000010481 ctxt->state = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010482 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010483 if (ret != 0)
10484 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010485#ifdef DEBUG
10486 else if (ctxt->errNr != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010487 ctxt->error(ctxt->userData,
10488 "%d Extra error messages left on stack !\n",
10489 ctxt->errNr);
10490 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010491 }
10492#endif
Daniel Veillardf54cd532004-02-25 11:52:31 +000010493#ifdef LIBXML_VALID_ENABLED
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010494 if (ctxt->idref == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010495 xmlValidCtxt vctxt;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010496
Daniel Veillard4c004142003-10-07 11:33:24 +000010497 memset(&vctxt, 0, sizeof(xmlValidCtxt));
10498 vctxt.valid = 1;
10499 vctxt.error = ctxt->error;
10500 vctxt.warning = ctxt->warning;
10501 vctxt.userData = ctxt->userData;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010502
Daniel Veillard4c004142003-10-07 11:33:24 +000010503 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10504 ret = -1;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010505 }
Daniel Veillardf54cd532004-02-25 11:52:31 +000010506#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010507 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
Daniel Veillard4c004142003-10-07 11:33:24 +000010508 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010509
Daniel Veillard4c004142003-10-07 11:33:24 +000010510 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010511}
10512
Daniel Veillardfd573f12003-03-16 17:52:32 +000010513/************************************************************************
10514 * *
10515 * Validation interfaces *
10516 * *
10517 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +000010518
Daniel Veillard6eadf632003-01-23 18:29:16 +000010519/**
10520 * xmlRelaxNGNewValidCtxt:
10521 * @schema: a precompiled XML RelaxNGs
10522 *
10523 * Create an XML RelaxNGs validation context based on the given schema
10524 *
10525 * Returns the validation context or NULL in case of error
10526 */
10527xmlRelaxNGValidCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +000010528xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10529{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010530 xmlRelaxNGValidCtxtPtr ret;
10531
10532 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10533 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010534 xmlRngVErrMemory(NULL, "building context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +000010535 return (NULL);
10536 }
10537 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10538 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +000010539 ret->error = xmlGenericError;
10540 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +000010541 ret->errNr = 0;
10542 ret->errMax = 0;
10543 ret->err = NULL;
10544 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010545 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +000010546 ret->states = NULL;
10547 ret->freeState = NULL;
10548 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010549 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010550 return (ret);
10551}
10552
10553/**
10554 * xmlRelaxNGFreeValidCtxt:
10555 * @ctxt: the schema validation context
10556 *
10557 * Free the resources associated to the schema validation context
10558 */
10559void
Daniel Veillard4c004142003-10-07 11:33:24 +000010560xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10561{
Daniel Veillard798024a2003-03-19 10:36:09 +000010562 int k;
10563
Daniel Veillard6eadf632003-01-23 18:29:16 +000010564 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010565 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010566 if (ctxt->states != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010567 xmlRelaxNGFreeStates(NULL, ctxt->states);
Daniel Veillard798024a2003-03-19 10:36:09 +000010568 if (ctxt->freeState != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010569 for (k = 0; k < ctxt->freeState->nbState; k++) {
10570 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10571 }
10572 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
Daniel Veillard798024a2003-03-19 10:36:09 +000010573 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010574 if (ctxt->freeStates != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010575 for (k = 0; k < ctxt->freeStatesNr; k++) {
10576 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10577 }
10578 xmlFree(ctxt->freeStates);
Daniel Veillard798024a2003-03-19 10:36:09 +000010579 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010580 if (ctxt->errTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010581 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010582 if (ctxt->elemTab != NULL) {
10583 xmlRegExecCtxtPtr exec;
10584
Daniel Veillard4c004142003-10-07 11:33:24 +000010585 exec = xmlRelaxNGElemPop(ctxt);
10586 while (exec != NULL) {
10587 xmlRegFreeExecCtxt(exec);
10588 exec = xmlRelaxNGElemPop(ctxt);
10589 }
10590 xmlFree(ctxt->elemTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010591 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010592 xmlFree(ctxt);
10593}
10594
10595/**
10596 * xmlRelaxNGSetValidErrors:
10597 * @ctxt: a Relax-NG validation context
10598 * @err: the error function
10599 * @warn: the warning function
10600 * @ctx: the functions context
10601 *
10602 * Set the error and warning callback informations
10603 */
10604void
10605xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010606 xmlRelaxNGValidityErrorFunc err,
10607 xmlRelaxNGValidityWarningFunc warn, void *ctx)
10608{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010609 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010610 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010611 ctxt->error = err;
10612 ctxt->warning = warn;
10613 ctxt->userData = ctx;
10614}
10615
10616/**
Daniel Veillard409a8142003-07-18 15:16:57 +000010617 * xmlRelaxNGGetValidErrors:
10618 * @ctxt: a Relax-NG validation context
10619 * @err: the error function result
10620 * @warn: the warning function result
10621 * @ctx: the functions context result
10622 *
10623 * Get the error and warning callback informations
10624 *
10625 * Returns -1 in case of error and 0 otherwise
10626 */
10627int
10628xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010629 xmlRelaxNGValidityErrorFunc * err,
10630 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
10631{
Daniel Veillard409a8142003-07-18 15:16:57 +000010632 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010633 return (-1);
10634 if (err != NULL)
10635 *err = ctxt->error;
10636 if (warn != NULL)
10637 *warn = ctxt->warning;
10638 if (ctx != NULL)
10639 *ctx = ctxt->userData;
10640 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +000010641}
10642
10643/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010644 * xmlRelaxNGValidateDoc:
10645 * @ctxt: a Relax-NG validation context
10646 * @doc: a parsed document tree
10647 *
10648 * Validate a document tree in memory.
10649 *
10650 * Returns 0 if the document is valid, a positive error code
10651 * number otherwise and -1 in case of internal or API error.
10652 */
10653int
Daniel Veillard4c004142003-10-07 11:33:24 +000010654xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10655{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010656 int ret;
10657
10658 if ((ctxt == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010659 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010660
10661 ctxt->doc = doc;
10662
10663 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010664 /*
10665 * TODO: build error codes
10666 */
10667 if (ret == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +000010668 return (1);
10669 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010670}
10671
10672#endif /* LIBXML_SCHEMAS_ENABLED */