blob: b1d4a771faa0045705ab9d0ad7a82875672c80c7 [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 Veillard42595322004-11-08 10:52:06 +0000251 int freedoc; /* need to free the document */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000252};
253
254#define FLAGS_IGNORABLE 1
255#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000256#define FLAGS_MIXED_CONTENT 4
Daniel Veillard6eadf632003-01-23 18:29:16 +0000257
258/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000259 * xmlRelaxNGInterleaveGroup:
260 *
261 * A RelaxNGs partition set associated to lists of definitions
262 */
263typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
264typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
265struct _xmlRelaxNGInterleaveGroup {
Daniel Veillard4c004142003-10-07 11:33:24 +0000266 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
267 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
268 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000269};
270
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000271#define IS_DETERMINIST 1
272#define IS_NEEDCHECK 2
Daniel Veillard4c004142003-10-07 11:33:24 +0000273
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000274/**
275 * xmlRelaxNGPartitions:
276 *
277 * A RelaxNGs partition associated to an interleave group
278 */
279typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
280typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
281struct _xmlRelaxNGPartition {
Daniel Veillard4c004142003-10-07 11:33:24 +0000282 int nbgroups; /* number of groups in the partitions */
283 xmlHashTablePtr triage; /* hash table used to direct nodes to the
284 * right group when possible */
285 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000286 xmlRelaxNGInterleaveGroupPtr *groups;
287};
288
289/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000290 * xmlRelaxNGValidState:
291 *
292 * A RelaxNGs validation state
293 */
294#define MAX_ATTR 20
295typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
296typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
297struct _xmlRelaxNGValidState {
Daniel Veillard4c004142003-10-07 11:33:24 +0000298 xmlNodePtr node; /* the current node */
299 xmlNodePtr seq; /* the sequence of children left to validate */
300 int nbAttrs; /* the number of attributes */
301 int maxAttrs; /* the size of attrs */
302 int nbAttrLeft; /* the number of attributes left to validate */
303 xmlChar *value; /* the value when operating on string */
304 xmlChar *endvalue; /* the end value when operating on string */
305 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000306};
307
308/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000309 * xmlRelaxNGStates:
310 *
311 * A RelaxNGs container for validation state
312 */
313typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
314typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
315struct _xmlRelaxNGStates {
Daniel Veillard4c004142003-10-07 11:33:24 +0000316 int nbState; /* the number of states */
317 int maxState; /* the size of the array */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000318 xmlRelaxNGValidStatePtr *tabState;
319};
320
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000321#define ERROR_IS_DUP 1
Daniel Veillard4c004142003-10-07 11:33:24 +0000322
Daniel Veillardfd573f12003-03-16 17:52:32 +0000323/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000324 * xmlRelaxNGValidError:
325 *
326 * A RelaxNGs validation error
327 */
328typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
329typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
330struct _xmlRelaxNGValidError {
Daniel Veillard4c004142003-10-07 11:33:24 +0000331 xmlRelaxNGValidErr err; /* the error number */
332 int flags; /* flags */
333 xmlNodePtr node; /* the current node */
334 xmlNodePtr seq; /* the current child */
335 const xmlChar *arg1; /* first arg */
336 const xmlChar *arg2; /* second arg */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000337};
338
339/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000340 * xmlRelaxNGValidCtxt:
341 *
342 * A RelaxNGs validation context
343 */
344
345struct _xmlRelaxNGValidCtxt {
Daniel Veillard4c004142003-10-07 11:33:24 +0000346 void *userData; /* user specific data block */
347 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
348 xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
Daniel Veillard659e71e2003-10-10 14:10:40 +0000349 xmlStructuredErrorFunc serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000350 int nbErrors; /* number of errors in validation */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000351
Daniel Veillard4c004142003-10-07 11:33:24 +0000352 xmlRelaxNGPtr schema; /* The schema in use */
353 xmlDocPtr doc; /* the document being validated */
354 int flags; /* validation flags */
355 int depth; /* validation depth */
356 int idref; /* requires idref checking */
357 int errNo; /* the first error found */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000358
359 /*
360 * Errors accumulated in branches may have to be stacked to be
361 * provided back when it's sure they affect validation.
362 */
363 xmlRelaxNGValidErrorPtr err; /* Last error */
Daniel Veillard4c004142003-10-07 11:33:24 +0000364 int errNr; /* Depth of the error stack */
365 int errMax; /* Max depth of the error stack */
366 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000367
Daniel Veillard4c004142003-10-07 11:33:24 +0000368 xmlRelaxNGValidStatePtr state; /* the current validation state */
369 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000370
Daniel Veillard4c004142003-10-07 11:33:24 +0000371 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
372 int freeStatesNr;
373 int freeStatesMax;
374 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillardf4e55762003-04-15 23:32:22 +0000375
376 /*
377 * This is used for "progressive" validation
378 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000379 xmlRegExecCtxtPtr elem; /* the current element regexp */
380 int elemNr; /* the number of element validated */
381 int elemMax; /* the max depth of elements */
382 xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
383 int pstate; /* progressive state */
384 xmlNodePtr pnode; /* the current node */
385 xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */
386 int perr; /* signal error in content model
387 * outside the regexp */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000388};
389
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000390/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000391 * xmlRelaxNGInclude:
392 *
393 * Structure associated to a RelaxNGs document element
394 */
395struct _xmlRelaxNGInclude {
Daniel Veillard4c004142003-10-07 11:33:24 +0000396 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
397 xmlChar *href; /* the normalized href value */
398 xmlDocPtr doc; /* the associated XML document */
399 xmlRelaxNGDefinePtr content; /* the definitions */
400 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000401};
402
403/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000404 * xmlRelaxNGDocument:
405 *
406 * Structure associated to a RelaxNGs document element
407 */
408struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000409 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillard4c004142003-10-07 11:33:24 +0000410 xmlChar *href; /* the normalized href value */
411 xmlDocPtr doc; /* the associated XML document */
412 xmlRelaxNGDefinePtr content; /* the definitions */
413 xmlRelaxNGPtr schema; /* the schema */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000414};
415
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000416
Daniel Veillard6eadf632003-01-23 18:29:16 +0000417/************************************************************************
Daniel Veillard4c004142003-10-07 11:33:24 +0000418 * *
419 * Some factorized error routines *
420 * *
421 ************************************************************************/
422
423/**
424 * xmlRngPErrMemory:
425 * @ctxt: an Relax-NG parser context
426 * @extra: extra informations
427 *
428 * Handle a redefinition of attribute error
429 */
430static void
431xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
432{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000433 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000434 xmlGenericErrorFunc channel = NULL;
435 void *data = NULL;
436
437 if (ctxt != NULL) {
438 channel = ctxt->error;
439 data = ctxt->userData;
440 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000441 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000442 }
443 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000444 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000445 NULL, NULL, XML_FROM_RELAXNGP,
446 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
447 NULL, NULL, 0, 0,
448 "Memory allocation failed : %s\n", extra);
449 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000450 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000451 NULL, NULL, XML_FROM_RELAXNGP,
452 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
453 NULL, NULL, 0, 0, "Memory allocation failed\n");
454}
455
456/**
457 * xmlRngVErrMemory:
458 * @ctxt: a Relax-NG validation context
459 * @extra: extra informations
460 *
461 * Handle a redefinition of attribute error
462 */
463static void
464xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
465{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000466 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000467 xmlGenericErrorFunc channel = NULL;
468 void *data = NULL;
469
470 if (ctxt != NULL) {
471 channel = ctxt->error;
472 data = ctxt->userData;
473 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000474 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000475 }
476 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000477 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000478 NULL, NULL, XML_FROM_RELAXNGV,
479 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
480 NULL, NULL, 0, 0,
481 "Memory allocation failed : %s\n", extra);
482 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000483 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000484 NULL, NULL, XML_FROM_RELAXNGV,
485 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
486 NULL, NULL, 0, 0, "Memory allocation failed\n");
487}
488
489/**
490 * xmlRngPErr:
491 * @ctxt: a Relax-NG parser context
492 * @node: the node raising the error
493 * @error: the error code
494 * @msg: message
495 * @str1: extra info
496 * @str2: extra info
497 *
498 * Handle a Relax NG Parsing error
499 */
500static void
501xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
502 const char *msg, const xmlChar * str1, const xmlChar * str2)
503{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000504 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000505 xmlGenericErrorFunc channel = NULL;
506 void *data = NULL;
507
508 if (ctxt != NULL) {
509 channel = ctxt->error;
510 data = ctxt->userData;
511 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000512 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000513 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000514 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000515 NULL, node, XML_FROM_RELAXNGP,
516 error, XML_ERR_ERROR, NULL, 0,
517 (const char *) str1, (const char *) str2, NULL, 0, 0,
518 msg, str1, str2);
519}
520
521/**
522 * xmlRngVErr:
523 * @ctxt: a Relax-NG validation context
524 * @node: the node raising the error
525 * @error: the error code
526 * @msg: message
527 * @str1: extra info
528 * @str2: extra info
529 *
530 * Handle a Relax NG Validation error
531 */
532static void
533xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
534 const char *msg, const xmlChar * str1, const xmlChar * str2)
535{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000536 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +0000537 xmlGenericErrorFunc channel = NULL;
538 void *data = NULL;
539
540 if (ctxt != NULL) {
541 channel = ctxt->error;
542 data = ctxt->userData;
543 ctxt->nbErrors++;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000544 schannel = ctxt->serror;
Daniel Veillard4c004142003-10-07 11:33:24 +0000545 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000546 __xmlRaiseError(schannel, channel, data,
Daniel Veillard4c004142003-10-07 11:33:24 +0000547 NULL, node, XML_FROM_RELAXNGV,
548 error, XML_ERR_ERROR, NULL, 0,
549 (const char *) str1, (const char *) str2, NULL, 0, 0,
550 msg, str1, str2);
551}
552
553/************************************************************************
Daniel Veillard6eadf632003-01-23 18:29:16 +0000554 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000555 * Preliminary type checking interfaces *
556 * *
557 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +0000558
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000559/**
560 * xmlRelaxNGTypeHave:
561 * @data: data needed for the library
562 * @type: the type name
563 * @value: the value to check
564 *
565 * Function provided by a type library to check if a type is exported
566 *
567 * Returns 1 if yes, 0 if no and -1 in case of error.
568 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000569typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000570
571/**
572 * xmlRelaxNGTypeCheck:
573 * @data: data needed for the library
574 * @type: the type name
575 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000576 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000577 *
578 * Function provided by a type library to check if a value match a type
579 *
580 * Returns 1 if yes, 0 if no and -1 in case of error.
581 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000582typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
583 const xmlChar * value, void **result,
584 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000585
586/**
587 * xmlRelaxNGFacetCheck:
588 * @data: data needed for the library
589 * @type: the type name
590 * @facet: the facet name
591 * @val: the facet value
592 * @strval: the string value
593 * @value: the value to check
594 *
595 * Function provided by a type library to check a value facet
596 *
597 * Returns 1 if yes, 0 if no and -1 in case of error.
598 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000599typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
600 const xmlChar * facet,
601 const xmlChar * val,
602 const xmlChar * strval, void *value);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000603
604/**
605 * xmlRelaxNGTypeFree:
606 * @data: data needed for the library
607 * @result: the value to free
608 *
609 * Function provided by a type library to free a returned result
610 */
611typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000612
613/**
614 * xmlRelaxNGTypeCompare:
615 * @data: data needed for the library
616 * @type: the type name
617 * @value1: the first value
618 * @value2: the second value
619 *
620 * Function provided by a type library to compare two values accordingly
621 * to a type.
622 *
623 * Returns 1 if yes, 0 if no and -1 in case of error.
624 */
Daniel Veillard4c004142003-10-07 11:33:24 +0000625typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
626 const xmlChar * value1,
627 xmlNodePtr ctxt1,
628 void *comp1,
629 const xmlChar * value2,
630 xmlNodePtr ctxt2);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000631typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
632typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
633struct _xmlRelaxNGTypeLibrary {
Daniel Veillard4c004142003-10-07 11:33:24 +0000634 const xmlChar *namespace; /* the datatypeLibrary value */
635 void *data; /* data needed for the library */
636 xmlRelaxNGTypeHave have; /* the export function */
637 xmlRelaxNGTypeCheck check; /* the checking function */
638 xmlRelaxNGTypeCompare comp; /* the compare function */
639 xmlRelaxNGFacetCheck facet; /* the facet check function */
640 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000641};
642
643/************************************************************************
644 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000645 * Allocation functions *
646 * *
647 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000648static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
649static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillard4c004142003-10-07 11:33:24 +0000650static void xmlRelaxNGNormExtSpace(xmlChar * value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000651static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillard4c004142003-10-07 11:33:24 +0000652static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
653 ATTRIBUTE_UNUSED,
654 xmlRelaxNGValidStatePtr state1,
655 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000656static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +0000657 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000658
659/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000660 * xmlRelaxNGFreeDocument:
661 * @docu: a document structure
662 *
663 * Deallocate a RelaxNG document structure.
664 */
665static void
666xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
667{
668 if (docu == NULL)
669 return;
670
671 if (docu->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000672 xmlFree(docu->href);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000673 if (docu->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000674 xmlFreeDoc(docu->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000675 if (docu->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000676 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000677 xmlFree(docu);
678}
679
680/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000681 * xmlRelaxNGFreeDocumentList:
682 * @docu: a list of document structure
683 *
684 * Deallocate a RelaxNG document structures.
685 */
686static void
687xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
688{
689 xmlRelaxNGDocumentPtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000690
Daniel Veillardc482e262003-02-26 14:48:48 +0000691 while (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000692 next = docu->next;
693 xmlRelaxNGFreeDocument(docu);
694 docu = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000695 }
696}
697
698/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000699 * xmlRelaxNGFreeInclude:
700 * @incl: a include structure
701 *
702 * Deallocate a RelaxNG include structure.
703 */
704static void
705xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
706{
707 if (incl == NULL)
708 return;
709
710 if (incl->href != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000711 xmlFree(incl->href);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000712 if (incl->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000713 xmlFreeDoc(incl->doc);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000714 if (incl->schema != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000715 xmlRelaxNGFree(incl->schema);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000716 xmlFree(incl);
717}
718
719/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000720 * xmlRelaxNGFreeIncludeList:
721 * @incl: a include structure list
722 *
723 * Deallocate a RelaxNG include structure.
724 */
725static void
726xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
727{
728 xmlRelaxNGIncludePtr next;
Daniel Veillard4c004142003-10-07 11:33:24 +0000729
Daniel Veillardc482e262003-02-26 14:48:48 +0000730 while (incl != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000731 next = incl->next;
732 xmlRelaxNGFreeInclude(incl);
733 incl = next;
Daniel Veillardc482e262003-02-26 14:48:48 +0000734 }
735}
736
737/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000738 * xmlRelaxNGNewRelaxNG:
739 * @ctxt: a Relax-NG validation context (optional)
740 *
741 * Allocate a new RelaxNG structure.
742 *
743 * Returns the newly allocated structure or NULL in case or error
744 */
745static xmlRelaxNGPtr
746xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
747{
748 xmlRelaxNGPtr ret;
749
750 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
751 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000752 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000753 return (NULL);
754 }
755 memset(ret, 0, sizeof(xmlRelaxNG));
756
757 return (ret);
758}
759
760/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000761 * xmlRelaxNGFreeInnerSchema:
762 * @schema: a schema structure
763 *
764 * Deallocate a RelaxNG schema structure.
765 */
766static void
767xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
768{
769 if (schema == NULL)
770 return;
771
772 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000773 xmlFreeDoc(schema->doc);
Daniel Veillardc482e262003-02-26 14:48:48 +0000774 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000775 int i;
Daniel Veillardc482e262003-02-26 14:48:48 +0000776
Daniel Veillard4c004142003-10-07 11:33:24 +0000777 for (i = 0; i < schema->defNr; i++)
778 xmlRelaxNGFreeDefine(schema->defTab[i]);
779 xmlFree(schema->defTab);
Daniel Veillardc482e262003-02-26 14:48:48 +0000780 }
781
782 xmlFree(schema);
783}
784
785/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000786 * xmlRelaxNGFree:
787 * @schema: a schema structure
788 *
789 * Deallocate a RelaxNG structure.
790 */
791void
792xmlRelaxNGFree(xmlRelaxNGPtr schema)
793{
794 if (schema == NULL)
795 return;
796
Daniel Veillard6eadf632003-01-23 18:29:16 +0000797 if (schema->topgrammar != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000798 xmlRelaxNGFreeGrammar(schema->topgrammar);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000799 if (schema->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000800 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000801 if (schema->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000802 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000803 if (schema->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000804 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000805 if (schema->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000806 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +0000807
Daniel Veillard4c004142003-10-07 11:33:24 +0000808 for (i = 0; i < schema->defNr; i++)
809 xmlRelaxNGFreeDefine(schema->defTab[i]);
810 xmlFree(schema->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +0000811 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000812
813 xmlFree(schema);
814}
815
816/**
817 * xmlRelaxNGNewGrammar:
818 * @ctxt: a Relax-NG validation context (optional)
819 *
820 * Allocate a new RelaxNG grammar.
821 *
822 * Returns the newly allocated structure or NULL in case or error
823 */
824static xmlRelaxNGGrammarPtr
825xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
826{
827 xmlRelaxNGGrammarPtr ret;
828
829 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
830 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000831 xmlRngPErrMemory(ctxt, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000832 return (NULL);
833 }
834 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
835
836 return (ret);
837}
838
839/**
840 * xmlRelaxNGFreeGrammar:
841 * @grammar: a grammar structure
842 *
843 * Deallocate a RelaxNG grammar structure.
844 */
845static void
846xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
847{
848 if (grammar == NULL)
849 return;
850
Daniel Veillardc482e262003-02-26 14:48:48 +0000851 if (grammar->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000852 xmlRelaxNGFreeGrammar(grammar->children);
Daniel Veillardc482e262003-02-26 14:48:48 +0000853 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000854 if (grammar->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000855 xmlRelaxNGFreeGrammar(grammar->next);
Daniel Veillard419a7682003-02-03 23:22:49 +0000856 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000857 if (grammar->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000858 xmlHashFree(grammar->refs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000859 }
860 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000861 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000862 }
863
864 xmlFree(grammar);
865}
866
867/**
868 * xmlRelaxNGNewDefine:
869 * @ctxt: a Relax-NG validation context
870 * @node: the node in the input document.
871 *
872 * Allocate a new RelaxNG define.
873 *
874 * Returns the newly allocated structure or NULL in case or error
875 */
876static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000877xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000878{
879 xmlRelaxNGDefinePtr ret;
880
Daniel Veillard419a7682003-02-03 23:22:49 +0000881 if (ctxt->defMax == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000882 ctxt->defMax = 16;
883 ctxt->defNr = 0;
884 ctxt->defTab = (xmlRelaxNGDefinePtr *)
885 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
886 if (ctxt->defTab == NULL) {
887 xmlRngPErrMemory(ctxt, "allocating define\n");
888 return (NULL);
889 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000890 } else if (ctxt->defMax <= ctxt->defNr) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000891 xmlRelaxNGDefinePtr *tmp;
892
893 ctxt->defMax *= 2;
894 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
895 ctxt->defMax *
896 sizeof
897 (xmlRelaxNGDefinePtr));
898 if (tmp == NULL) {
899 xmlRngPErrMemory(ctxt, "allocating define\n");
900 return (NULL);
901 }
902 ctxt->defTab = tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +0000903 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000904 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
905 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000906 xmlRngPErrMemory(ctxt, "allocating define\n");
907 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000908 }
909 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000910 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000911 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000912 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000913 return (ret);
914}
915
916/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000917 * xmlRelaxNGFreePartition:
918 * @partitions: a partition set structure
919 *
920 * Deallocate RelaxNG partition set structures.
921 */
922static void
Daniel Veillard4c004142003-10-07 11:33:24 +0000923xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
924{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000925 xmlRelaxNGInterleaveGroupPtr group;
926 int j;
927
928 if (partitions != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +0000929 if (partitions->groups != NULL) {
930 for (j = 0; j < partitions->nbgroups; j++) {
931 group = partitions->groups[j];
932 if (group != NULL) {
933 if (group->defs != NULL)
934 xmlFree(group->defs);
935 if (group->attrs != NULL)
936 xmlFree(group->attrs);
937 xmlFree(group);
938 }
939 }
940 xmlFree(partitions->groups);
941 }
942 if (partitions->triage != NULL) {
943 xmlHashFree(partitions->triage, NULL);
944 }
945 xmlFree(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000946 }
947}
Daniel Veillard4c004142003-10-07 11:33:24 +0000948
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000949/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000950 * xmlRelaxNGFreeDefine:
951 * @define: a define structure
952 *
953 * Deallocate a RelaxNG define structure.
954 */
955static void
956xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
957{
958 if (define == NULL)
959 return;
960
Daniel Veillard4c004142003-10-07 11:33:24 +0000961 if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
962 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000963
Daniel Veillard4c004142003-10-07 11:33:24 +0000964 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
965 if ((lib != NULL) && (lib->freef != NULL))
966 lib->freef(lib->data, (void *) define->attrs);
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000967 }
Daniel Veillard4c004142003-10-07 11:33:24 +0000968 if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
969 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
970 if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
971 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000972 if (define->name != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000973 xmlFree(define->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000974 if (define->ns != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000975 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000976 if (define->value != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +0000977 xmlFree(define->value);
Daniel Veillard52b48c72003-04-13 19:53:42 +0000978 if (define->contModel != NULL)
979 xmlRegFreeRegexp(define->contModel);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000980 xmlFree(define);
981}
982
983/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000984 * xmlRelaxNGNewStates:
985 * @ctxt: a Relax-NG validation context
986 * @size: the default size for the container
987 *
988 * Allocate a new RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000989 *
990 * Returns the newly allocated structure or NULL in case or error
991 */
992static xmlRelaxNGStatesPtr
993xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
994{
995 xmlRelaxNGStatesPtr ret;
996
Daniel Veillard798024a2003-03-19 10:36:09 +0000997 if ((ctxt != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +0000998 (ctxt->freeState != NULL) && (ctxt->freeStatesNr > 0)) {
999 ctxt->freeStatesNr--;
1000 ret = ctxt->freeStates[ctxt->freeStatesNr];
1001 ret->nbState = 0;
1002 return (ret);
Daniel Veillard798024a2003-03-19 10:36:09 +00001003 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001004 if (size < 16)
1005 size = 16;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001006
1007 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
Daniel Veillard4c004142003-10-07 11:33:24 +00001008 (size -
1009 1) *
1010 sizeof(xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001011 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001012 xmlRngVErrMemory(ctxt, "allocating states\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001013 return (NULL);
1014 }
1015 ret->nbState = 0;
1016 ret->maxState = size;
Daniel Veillard4c004142003-10-07 11:33:24 +00001017 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
1018 sizeof
1019 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001020 if (ret->tabState == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001021 xmlRngVErrMemory(ctxt, "allocating states\n");
1022 xmlFree(ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001023 return (NULL);
1024 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001025 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001026}
1027
1028/**
Daniel Veillard798024a2003-03-19 10:36:09 +00001029 * xmlRelaxNGAddStateUniq:
1030 * @ctxt: a Relax-NG validation context
1031 * @states: the states container
1032 * @state: the validation state
1033 *
1034 * Add a RelaxNG validation state to the container without checking
1035 * for unicity.
1036 *
1037 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1038 */
1039static int
1040xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001041 xmlRelaxNGStatesPtr states,
1042 xmlRelaxNGValidStatePtr state)
Daniel Veillard798024a2003-03-19 10:36:09 +00001043{
1044 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001045 return (-1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001046 }
1047 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001048 xmlRelaxNGValidStatePtr *tmp;
1049 int size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001050
Daniel Veillard4c004142003-10-07 11:33:24 +00001051 size = states->maxState * 2;
1052 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1053 (size) *
1054 sizeof
1055 (xmlRelaxNGValidStatePtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001056 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001057 xmlRngVErrMemory(ctxt, "adding states\n");
1058 return (-1);
1059 }
1060 states->tabState = tmp;
1061 states->maxState = size;
Daniel Veillard798024a2003-03-19 10:36:09 +00001062 }
1063 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001064 return (1);
Daniel Veillard798024a2003-03-19 10:36:09 +00001065}
1066
1067/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001068 * xmlRelaxNGAddState:
1069 * @ctxt: a Relax-NG validation context
1070 * @states: the states container
1071 * @state: the validation state
1072 *
1073 * Add a RelaxNG validation state to the container
1074 *
1075 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1076 */
1077static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001078xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
1079 xmlRelaxNGStatesPtr states,
1080 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001081{
1082 int i;
1083
1084 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001085 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001086 }
1087 if (states->nbState >= states->maxState) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001088 xmlRelaxNGValidStatePtr *tmp;
1089 int size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001090
Daniel Veillard4c004142003-10-07 11:33:24 +00001091 size = states->maxState * 2;
1092 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1093 (size) *
1094 sizeof
1095 (xmlRelaxNGValidStatePtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001096 if (tmp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001097 xmlRngVErrMemory(ctxt, "adding states\n");
1098 return (-1);
1099 }
1100 states->tabState = tmp;
1101 states->maxState = size;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001102 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001103 for (i = 0; i < states->nbState; i++) {
1104 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
1105 xmlRelaxNGFreeValidState(ctxt, state);
1106 return (0);
1107 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001108 }
1109 states->tabState[states->nbState++] = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00001110 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001111}
1112
1113/**
1114 * xmlRelaxNGFreeStates:
1115 * @ctxt: a Relax-NG validation context
1116 * @states: teh container
1117 *
1118 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +00001119 */
1120static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001121xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001122 xmlRelaxNGStatesPtr states)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001123{
Daniel Veillard798024a2003-03-19 10:36:09 +00001124 if (states == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001125 return;
Daniel Veillard798024a2003-03-19 10:36:09 +00001126 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001127 ctxt->freeStatesMax = 40;
1128 ctxt->freeStatesNr = 0;
1129 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
1130 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
1131 if (ctxt->freeStates == NULL) {
1132 xmlRngVErrMemory(ctxt, "storing states\n");
1133 }
1134 } else if ((ctxt != NULL)
1135 && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
1136 xmlRelaxNGStatesPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001137
Daniel Veillard4c004142003-10-07 11:33:24 +00001138 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
1139 2 * ctxt->freeStatesMax *
1140 sizeof
1141 (xmlRelaxNGStatesPtr));
1142 if (tmp == NULL) {
1143 xmlRngVErrMemory(ctxt, "storing states\n");
1144 xmlFree(states->tabState);
1145 xmlFree(states);
1146 return;
1147 }
1148 ctxt->freeStates = tmp;
1149 ctxt->freeStatesMax *= 2;
Daniel Veillard798024a2003-03-19 10:36:09 +00001150 }
1151 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001152 xmlFree(states->tabState);
1153 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +00001154 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001155 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001156 }
1157}
1158
1159/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001160 * xmlRelaxNGNewValidState:
1161 * @ctxt: a Relax-NG validation context
1162 * @node: the current node or NULL for the document
1163 *
1164 * Allocate a new RelaxNG validation state
1165 *
1166 * Returns the newly allocated structure or NULL in case or error
1167 */
1168static xmlRelaxNGValidStatePtr
1169xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1170{
1171 xmlRelaxNGValidStatePtr ret;
1172 xmlAttrPtr attr;
1173 xmlAttrPtr attrs[MAX_ATTR];
1174 int nbAttrs = 0;
1175 xmlNodePtr root = NULL;
1176
1177 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001178 root = xmlDocGetRootElement(ctxt->doc);
1179 if (root == NULL)
1180 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001181 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001182 attr = node->properties;
1183 while (attr != NULL) {
1184 if (nbAttrs < MAX_ATTR)
1185 attrs[nbAttrs++] = attr;
1186 else
1187 nbAttrs++;
1188 attr = attr->next;
1189 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001190 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001191 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1192 ctxt->freeState->nbState--;
1193 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001194 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001195 ret =
1196 (xmlRelaxNGValidStatePtr)
1197 xmlMalloc(sizeof(xmlRelaxNGValidState));
1198 if (ret == NULL) {
1199 xmlRngVErrMemory(ctxt, "allocating states\n");
1200 return (NULL);
1201 }
1202 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001203 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001204 ret->value = NULL;
1205 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001206 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001207 ret->node = (xmlNodePtr) ctxt->doc;
1208 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001209 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001210 ret->node = node;
1211 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001212 }
1213 ret->nbAttrs = 0;
1214 if (nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001215 if (ret->attrs == NULL) {
1216 if (nbAttrs < 4)
1217 ret->maxAttrs = 4;
1218 else
1219 ret->maxAttrs = nbAttrs;
1220 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1221 sizeof(xmlAttrPtr));
1222 if (ret->attrs == NULL) {
1223 xmlRngVErrMemory(ctxt, "allocating states\n");
1224 return (ret);
1225 }
1226 } else if (ret->maxAttrs < nbAttrs) {
1227 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001228
Daniel Veillard4c004142003-10-07 11:33:24 +00001229 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1230 sizeof(xmlAttrPtr));
1231 if (tmp == NULL) {
1232 xmlRngVErrMemory(ctxt, "allocating states\n");
1233 return (ret);
1234 }
1235 ret->attrs = tmp;
1236 ret->maxAttrs = nbAttrs;
1237 }
1238 ret->nbAttrs = nbAttrs;
1239 if (nbAttrs < MAX_ATTR) {
1240 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1241 } else {
1242 attr = node->properties;
1243 nbAttrs = 0;
1244 while (attr != NULL) {
1245 ret->attrs[nbAttrs++] = attr;
1246 attr = attr->next;
1247 }
1248 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001249 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001250 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001251 return (ret);
1252}
1253
1254/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001255 * xmlRelaxNGCopyValidState:
1256 * @ctxt: a Relax-NG validation context
1257 * @state: a validation state
1258 *
1259 * Copy the validation state
1260 *
1261 * Returns the newly allocated structure or NULL in case or error
1262 */
1263static xmlRelaxNGValidStatePtr
1264xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001265 xmlRelaxNGValidStatePtr state)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001266{
1267 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001268 unsigned int maxAttrs;
1269 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001270
1271 if (state == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001272 return (NULL);
1273 if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1274 ctxt->freeState->nbState--;
1275 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
Daniel Veillard798024a2003-03-19 10:36:09 +00001276 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001277 ret =
1278 (xmlRelaxNGValidStatePtr)
1279 xmlMalloc(sizeof(xmlRelaxNGValidState));
1280 if (ret == NULL) {
1281 xmlRngVErrMemory(ctxt, "allocating states\n");
1282 return (NULL);
1283 }
1284 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001285 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001286 attrs = ret->attrs;
1287 maxAttrs = ret->maxAttrs;
1288 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1289 ret->attrs = attrs;
1290 ret->maxAttrs = maxAttrs;
1291 if (state->nbAttrs > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001292 if (ret->attrs == NULL) {
1293 ret->maxAttrs = state->maxAttrs;
1294 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1295 sizeof(xmlAttrPtr));
1296 if (ret->attrs == NULL) {
1297 xmlRngVErrMemory(ctxt, "allocating states\n");
1298 ret->nbAttrs = 0;
1299 return (ret);
1300 }
1301 } else if (ret->maxAttrs < state->nbAttrs) {
1302 xmlAttrPtr *tmp;
Daniel Veillard798024a2003-03-19 10:36:09 +00001303
Daniel Veillard4c004142003-10-07 11:33:24 +00001304 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1305 sizeof(xmlAttrPtr));
1306 if (tmp == NULL) {
1307 xmlRngVErrMemory(ctxt, "allocating states\n");
1308 ret->nbAttrs = 0;
1309 return (ret);
1310 }
1311 ret->maxAttrs = state->maxAttrs;
1312 ret->attrs = tmp;
1313 }
1314 memcpy(ret->attrs, state->attrs,
1315 state->nbAttrs * sizeof(xmlAttrPtr));
Daniel Veillard798024a2003-03-19 10:36:09 +00001316 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001317 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001318}
1319
1320/**
1321 * xmlRelaxNGEqualValidState:
1322 * @ctxt: a Relax-NG validation context
1323 * @state1: a validation state
1324 * @state2: a validation state
1325 *
1326 * Compare the validation states for equality
1327 *
1328 * Returns 1 if equald, 0 otherwise
1329 */
1330static int
1331xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00001332 xmlRelaxNGValidStatePtr state1,
1333 xmlRelaxNGValidStatePtr state2)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001334{
1335 int i;
1336
1337 if ((state1 == NULL) || (state2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00001338 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001339 if (state1 == state2)
Daniel Veillard4c004142003-10-07 11:33:24 +00001340 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001341 if (state1->node != state2->node)
Daniel Veillard4c004142003-10-07 11:33:24 +00001342 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001343 if (state1->seq != state2->seq)
Daniel Veillard4c004142003-10-07 11:33:24 +00001344 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001345 if (state1->nbAttrLeft != state2->nbAttrLeft)
Daniel Veillard4c004142003-10-07 11:33:24 +00001346 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001347 if (state1->nbAttrs != state2->nbAttrs)
Daniel Veillard4c004142003-10-07 11:33:24 +00001348 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001349 if (state1->endvalue != state2->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00001350 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001351 if ((state1->value != state2->value) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001352 (!xmlStrEqual(state1->value, state2->value)))
1353 return (0);
1354 for (i = 0; i < state1->nbAttrs; i++) {
1355 if (state1->attrs[i] != state2->attrs[i])
1356 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001357 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001358 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001359}
1360
1361/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001362 * xmlRelaxNGFreeValidState:
1363 * @state: a validation state structure
1364 *
1365 * Deallocate a RelaxNG validation state structure.
1366 */
1367static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001368xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001369 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001370{
1371 if (state == NULL)
1372 return;
1373
Daniel Veillard798024a2003-03-19 10:36:09 +00001374 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001375 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
Daniel Veillard798024a2003-03-19 10:36:09 +00001376 }
1377 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001378 if (state->attrs != NULL)
1379 xmlFree(state->attrs);
1380 xmlFree(state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001381 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001382 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
Daniel Veillard798024a2003-03-19 10:36:09 +00001383 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001384}
1385
1386/************************************************************************
1387 * *
Daniel Veillard03c2f0a2004-01-25 19:54:59 +00001388 * Semi internal functions *
1389 * *
1390 ************************************************************************/
1391
1392/**
1393 * xmlRelaxParserSetFlag:
1394 * @ctxt: a RelaxNG parser context
1395 * @flags: a set of flags values
1396 *
1397 * Semi private function used to pass informations to a parser context
1398 * which are a combination of xmlRelaxNGParserFlag .
1399 *
1400 * Returns 0 if success and -1 in case of error
1401 */
1402int
1403xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
1404{
1405 if (ctxt == NULL) return(-1);
1406 if (flags & XML_RELAXNGP_FREE_DOC) {
1407 ctxt->crng |= XML_RELAXNGP_FREE_DOC;
1408 flags -= XML_RELAXNGP_FREE_DOC;
1409 }
1410 if (flags & XML_RELAXNGP_CRNG) {
1411 ctxt->crng |= XML_RELAXNGP_CRNG;
1412 flags -= XML_RELAXNGP_CRNG;
1413 }
1414 if (flags != 0) return(-1);
1415 return(0);
1416}
1417
1418/************************************************************************
1419 * *
1420 * Document functions *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001421 * *
1422 ************************************************************************/
1423static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001424 xmlDocPtr doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001425
1426/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001427 * xmlRelaxNGIncludePush:
1428 * @ctxt: the parser context
1429 * @value: the element doc
1430 *
1431 * Pushes a new include on top of the include stack
1432 *
1433 * Returns 0 in case of error, the index in the stack otherwise
1434 */
1435static int
1436xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001437 xmlRelaxNGIncludePtr value)
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001438{
1439 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001440 ctxt->incMax = 4;
1441 ctxt->incNr = 0;
1442 ctxt->incTab =
1443 (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
1444 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001445 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001446 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001447 return (0);
1448 }
1449 }
1450 if (ctxt->incNr >= ctxt->incMax) {
1451 ctxt->incMax *= 2;
1452 ctxt->incTab =
1453 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001454 ctxt->incMax *
1455 sizeof(ctxt->incTab[0]));
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001456 if (ctxt->incTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001457 xmlRngPErrMemory(ctxt, "allocating include\n");
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001458 return (0);
1459 }
1460 }
1461 ctxt->incTab[ctxt->incNr] = value;
1462 ctxt->inc = value;
1463 return (ctxt->incNr++);
1464}
1465
1466/**
1467 * xmlRelaxNGIncludePop:
1468 * @ctxt: the parser context
1469 *
1470 * Pops the top include from the include stack
1471 *
1472 * Returns the include just removed
1473 */
1474static xmlRelaxNGIncludePtr
1475xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1476{
1477 xmlRelaxNGIncludePtr ret;
1478
1479 if (ctxt->incNr <= 0)
1480 return (0);
1481 ctxt->incNr--;
1482 if (ctxt->incNr > 0)
1483 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1484 else
1485 ctxt->inc = NULL;
1486 ret = ctxt->incTab[ctxt->incNr];
1487 ctxt->incTab[ctxt->incNr] = 0;
1488 return (ret);
1489}
1490
1491/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001492 * xmlRelaxNGRemoveRedefine:
1493 * @ctxt: the parser context
1494 * @URL: the normalized URL
1495 * @target: the included target
1496 * @name: the define name to eliminate
1497 *
1498 * Applies the elimination algorithm of 4.7
1499 *
1500 * Returns 0 in case of error, 1 in case of success.
1501 */
1502static int
1503xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001504 const xmlChar * URL ATTRIBUTE_UNUSED,
1505 xmlNodePtr target, const xmlChar * name)
1506{
Daniel Veillard5add8682003-03-10 13:13:58 +00001507 int found = 0;
1508 xmlNodePtr tmp, tmp2;
1509 xmlChar *name2;
1510
1511#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001512 if (name == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00001513 xmlGenericError(xmlGenericErrorContext,
1514 "Elimination of <include> start from %s\n", URL);
Daniel Veillard952379b2003-03-17 15:37:12 +00001515 else
Daniel Veillard4c004142003-10-07 11:33:24 +00001516 xmlGenericError(xmlGenericErrorContext,
1517 "Elimination of <include> define %s from %s\n",
1518 name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001519#endif
1520 tmp = target;
1521 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001522 tmp2 = tmp->next;
1523 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1524 found = 1;
1525 xmlUnlinkNode(tmp);
1526 xmlFreeNode(tmp);
1527 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1528 name2 = xmlGetProp(tmp, BAD_CAST "name");
1529 xmlRelaxNGNormExtSpace(name2);
1530 if (name2 != NULL) {
1531 if (xmlStrEqual(name, name2)) {
1532 found = 1;
1533 xmlUnlinkNode(tmp);
1534 xmlFreeNode(tmp);
1535 }
1536 xmlFree(name2);
1537 }
1538 } else if (IS_RELAXNG(tmp, "include")) {
1539 xmlChar *href = NULL;
Daniel Veillard807daf82004-02-22 22:13:27 +00001540 xmlRelaxNGDocumentPtr inc = tmp->psvi;
Daniel Veillard5add8682003-03-10 13:13:58 +00001541
Daniel Veillard4c004142003-10-07 11:33:24 +00001542 if ((inc != NULL) && (inc->doc != NULL) &&
1543 (inc->doc->children != NULL)) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001544
Daniel Veillard4c004142003-10-07 11:33:24 +00001545 if (xmlStrEqual
1546 (inc->doc->children->name, BAD_CAST "grammar")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001547#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001548 href = xmlGetProp(tmp, BAD_CAST "href");
Daniel Veillard5add8682003-03-10 13:13:58 +00001549#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00001550 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1551 inc->doc->children->
1552 children, name) == 1) {
1553 found = 1;
1554 }
1555 if (href != NULL)
1556 xmlFree(href);
1557 }
1558 }
1559 }
1560 tmp = tmp2;
Daniel Veillard5add8682003-03-10 13:13:58 +00001561 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001562 return (found);
Daniel Veillard5add8682003-03-10 13:13:58 +00001563}
1564
1565/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001566 * xmlRelaxNGLoadInclude:
1567 * @ctxt: the parser context
1568 * @URL: the normalized URL
1569 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001570 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001571 *
1572 * First lookup if the document is already loaded into the parser context,
1573 * check against recursion. If not found the resource is loaded and
1574 * the content is preprocessed before being returned back to the caller.
1575 *
1576 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1577 */
1578static xmlRelaxNGIncludePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001579xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
1580 xmlNodePtr node, const xmlChar * ns)
1581{
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001582 xmlRelaxNGIncludePtr ret = NULL;
1583 xmlDocPtr doc;
1584 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001585 xmlNodePtr root, cur;
1586
1587#ifdef DEBUG_INCLUDE
1588 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001589 "xmlRelaxNGLoadInclude(%s)\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001590#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001591
1592 /*
1593 * check against recursion in the stack
1594 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001595 for (i = 0; i < ctxt->incNr; i++) {
1596 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1597 xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
1598 "Detected an Include recursion for %s\n", URL,
1599 NULL);
1600 return (NULL);
1601 }
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001602 }
1603
1604 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001605 * load the document
1606 */
Daniel Veillard87247e82004-01-13 20:42:02 +00001607 doc = xmlReadFile((const char *) URL,NULL,0);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001608 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001609 xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
1610 "xmlRelaxNG: could not load %s\n", URL, NULL);
1611 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001612 }
Daniel Veillard5add8682003-03-10 13:13:58 +00001613#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001614 xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001615#endif
1616
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001617 /*
1618 * Allocate the document structures and register it first.
1619 */
1620 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1621 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001622 xmlRngPErrMemory(ctxt, "allocating include\n");
1623 xmlFreeDoc(doc);
1624 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001625 }
1626 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1627 ret->doc = doc;
1628 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001629 ret->next = ctxt->includes;
1630 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001631
1632 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001633 * transmit the ns if needed
1634 */
1635 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001636 root = xmlDocGetRootElement(doc);
1637 if (root != NULL) {
1638 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1639 xmlSetProp(root, BAD_CAST "ns", ns);
1640 }
1641 }
Daniel Veillard416589a2003-02-17 17:25:42 +00001642 }
1643
1644 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001645 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001646 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001647 xmlRelaxNGIncludePush(ctxt, ret);
1648
1649 /*
1650 * Some preprocessing of the document content, this include recursing
1651 * in the include stack.
1652 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001653#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001654 xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001655#endif
1656
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001657 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1658 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001659 ctxt->inc = NULL;
1660 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001661 }
1662
1663 /*
1664 * Pop up the include from the stack
1665 */
1666 xmlRelaxNGIncludePop(ctxt);
1667
Daniel Veillard5add8682003-03-10 13:13:58 +00001668#ifdef DEBUG_INCLUDE
Daniel Veillard4c004142003-10-07 11:33:24 +00001669 xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001670#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001671 /*
1672 * Check that the top element is a grammar
1673 */
1674 root = xmlDocGetRootElement(doc);
1675 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001676 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
1677 "xmlRelaxNG: included document is empty %s\n", URL,
1678 NULL);
1679 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001680 }
1681 if (!IS_RELAXNG(root, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001682 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
1683 "xmlRelaxNG: included document %s root is not a grammar\n",
1684 URL, NULL);
1685 return (NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001686 }
1687
1688 /*
1689 * Elimination of redefined rules in the include.
1690 */
1691 cur = node->children;
1692 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001693 if (IS_RELAXNG(cur, "start")) {
1694 int found = 0;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001695
Daniel Veillard4c004142003-10-07 11:33:24 +00001696 found =
1697 xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
1698 if (!found) {
1699 xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
1700 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1701 URL, NULL);
1702 }
1703 } else if (IS_RELAXNG(cur, "define")) {
1704 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001705
Daniel Veillard4c004142003-10-07 11:33:24 +00001706 name = xmlGetProp(cur, BAD_CAST "name");
1707 if (name == NULL) {
1708 xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
1709 "xmlRelaxNG: include %s has define without name\n",
1710 URL, NULL);
1711 } else {
1712 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001713
Daniel Veillard4c004142003-10-07 11:33:24 +00001714 xmlRelaxNGNormExtSpace(name);
1715 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1716 root->children, name);
1717 if (!found) {
1718 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
1719 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1720 URL, name);
1721 }
1722 xmlFree(name);
1723 }
1724 }
1725 cur = cur->next;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001726 }
1727
1728
Daniel Veillard4c004142003-10-07 11:33:24 +00001729 return (ret);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001730}
1731
1732/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001733 * xmlRelaxNGValidErrorPush:
1734 * @ctxt: the validation context
1735 * @err: the error code
1736 * @arg1: the first string argument
1737 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001738 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001739 *
1740 * Pushes a new error on top of the error stack
1741 *
1742 * Returns 0 in case of error, the index in the stack otherwise
1743 */
1744static int
Daniel Veillard4c004142003-10-07 11:33:24 +00001745xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
1746 xmlRelaxNGValidErr err, const xmlChar * arg1,
1747 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001748{
1749 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00001750
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001751#ifdef DEBUG_ERROR
1752 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00001753 "Pushing error %d at %d on stack\n", err, ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001754#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00001755 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001756 ctxt->errMax = 8;
1757 ctxt->errNr = 0;
1758 ctxt->errTab =
1759 (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
1760 sizeof
1761 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001762 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001763 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001764 return (0);
1765 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001766 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001767 }
1768 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001769 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001770 ctxt->errTab =
1771 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001772 ctxt->errMax *
1773 sizeof
1774 (xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001775 if (ctxt->errTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001776 xmlRngVErrMemory(ctxt, "pushing error\n");
Daniel Veillard42f12e92003-03-07 18:32:59 +00001777 return (0);
1778 }
Daniel Veillard4c004142003-10-07 11:33:24 +00001779 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001780 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001781 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00001782 (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
1783 return (ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001784 cur = &ctxt->errTab[ctxt->errNr];
1785 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001786 if (dup) {
1787 cur->arg1 = xmlStrdup(arg1);
1788 cur->arg2 = xmlStrdup(arg2);
Daniel Veillard4c004142003-10-07 11:33:24 +00001789 cur->flags = ERROR_IS_DUP;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001790 } else {
1791 cur->arg1 = arg1;
1792 cur->arg2 = arg2;
Daniel Veillard4c004142003-10-07 11:33:24 +00001793 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001794 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001795 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001796 cur->node = ctxt->state->node;
1797 cur->seq = ctxt->state->seq;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001798 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00001799 cur->node = NULL;
1800 cur->seq = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001801 }
1802 ctxt->err = cur;
1803 return (ctxt->errNr++);
1804}
1805
1806/**
1807 * xmlRelaxNGValidErrorPop:
1808 * @ctxt: the validation context
1809 *
1810 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001811 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001812static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001813xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1814{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001815 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001816
Daniel Veillard580ced82003-03-21 21:22:48 +00001817 if (ctxt->errNr <= 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001818 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001819 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001820 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001821 ctxt->errNr--;
1822 if (ctxt->errNr > 0)
1823 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1824 else
1825 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001826 cur = &ctxt->errTab[ctxt->errNr];
1827 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001828 if (cur->arg1 != NULL)
1829 xmlFree((xmlChar *) cur->arg1);
1830 cur->arg1 = NULL;
1831 if (cur->arg2 != NULL)
1832 xmlFree((xmlChar *) cur->arg2);
1833 cur->arg2 = NULL;
1834 cur->flags = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001835 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001836}
1837
Daniel Veillard42f12e92003-03-07 18:32:59 +00001838/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001839 * xmlRelaxNGDocumentPush:
1840 * @ctxt: the parser context
1841 * @value: the element doc
1842 *
1843 * Pushes a new doc on top of the doc stack
1844 *
1845 * Returns 0 in case of error, the index in the stack otherwise
1846 */
1847static int
1848xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00001849 xmlRelaxNGDocumentPtr value)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001850{
1851 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001852 ctxt->docMax = 4;
1853 ctxt->docNr = 0;
1854 ctxt->docTab =
1855 (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
1856 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001857 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001858 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001859 return (0);
1860 }
1861 }
1862 if (ctxt->docNr >= ctxt->docMax) {
1863 ctxt->docMax *= 2;
1864 ctxt->docTab =
1865 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00001866 ctxt->docMax *
1867 sizeof(ctxt->docTab[0]));
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001868 if (ctxt->docTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001869 xmlRngPErrMemory(ctxt, "adding document\n");
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001870 return (0);
1871 }
1872 }
1873 ctxt->docTab[ctxt->docNr] = value;
1874 ctxt->doc = value;
1875 return (ctxt->docNr++);
1876}
1877
1878/**
1879 * xmlRelaxNGDocumentPop:
1880 * @ctxt: the parser context
1881 *
1882 * Pops the top doc from the doc stack
1883 *
1884 * Returns the doc just removed
1885 */
1886static xmlRelaxNGDocumentPtr
1887xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1888{
1889 xmlRelaxNGDocumentPtr ret;
1890
1891 if (ctxt->docNr <= 0)
1892 return (0);
1893 ctxt->docNr--;
1894 if (ctxt->docNr > 0)
1895 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1896 else
1897 ctxt->doc = NULL;
1898 ret = ctxt->docTab[ctxt->docNr];
1899 ctxt->docTab[ctxt->docNr] = 0;
1900 return (ret);
1901}
1902
1903/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001904 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001905 * @ctxt: the parser context
1906 * @URL: the normalized URL
1907 * @ns: the inherited ns if any
1908 *
1909 * First lookup if the document is already loaded into the parser context,
1910 * check against recursion. If not found the resource is loaded and
1911 * the content is preprocessed before being returned back to the caller.
1912 *
1913 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1914 */
1915static xmlRelaxNGDocumentPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00001916xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
1917 const xmlChar * URL, const xmlChar * ns)
1918{
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001919 xmlRelaxNGDocumentPtr ret = NULL;
1920 xmlDocPtr doc;
1921 xmlNodePtr root;
1922 int i;
1923
1924 /*
1925 * check against recursion in the stack
1926 */
Daniel Veillard4c004142003-10-07 11:33:24 +00001927 for (i = 0; i < ctxt->docNr; i++) {
1928 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1929 xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
1930 "Detected an externalRef recursion for %s\n", URL,
1931 NULL);
1932 return (NULL);
1933 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001934 }
1935
1936 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001937 * load the document
1938 */
Daniel Veillard87247e82004-01-13 20:42:02 +00001939 doc = xmlReadFile((const char *) URL,NULL,0);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001940 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001941 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
1942 "xmlRelaxNG: could not load %s\n", URL, NULL);
1943 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001944 }
1945
1946 /*
1947 * Allocate the document structures and register it first.
1948 */
1949 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1950 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001951 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
1952 "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
1953 xmlFreeDoc(doc);
1954 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001955 }
1956 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1957 ret->doc = doc;
1958 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001959 ret->next = ctxt->documents;
1960 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001961
1962 /*
1963 * transmit the ns if needed
1964 */
1965 if (ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001966 root = xmlDocGetRootElement(doc);
1967 if (root != NULL) {
1968 if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1969 xmlSetProp(root, BAD_CAST "ns", ns);
1970 }
1971 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001972 }
1973
1974 /*
1975 * push it on the stack and register it in the hash table
1976 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001977 xmlRelaxNGDocumentPush(ctxt, ret);
1978
1979 /*
1980 * Some preprocessing of the document content
1981 */
1982 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1983 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00001984 ctxt->doc = NULL;
1985 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001986 }
1987
1988 xmlRelaxNGDocumentPop(ctxt);
1989
Daniel Veillard4c004142003-10-07 11:33:24 +00001990 return (ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001991}
1992
1993/************************************************************************
1994 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001995 * Error functions *
1996 * *
1997 ************************************************************************/
1998
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001999#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
2000#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2001#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2002#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2003#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002004
Daniel Veillard231d7912003-02-09 14:22:17 +00002005static const char *
Daniel Veillard4c004142003-10-07 11:33:24 +00002006xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
2007{
Daniel Veillard231d7912003-02-09 14:22:17 +00002008 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002009 return ("none");
2010 switch (def->type) {
2011 case XML_RELAXNG_EMPTY:
2012 return ("empty");
2013 case XML_RELAXNG_NOT_ALLOWED:
2014 return ("notAllowed");
2015 case XML_RELAXNG_EXCEPT:
2016 return ("except");
2017 case XML_RELAXNG_TEXT:
2018 return ("text");
2019 case XML_RELAXNG_ELEMENT:
2020 return ("element");
2021 case XML_RELAXNG_DATATYPE:
2022 return ("datatype");
2023 case XML_RELAXNG_VALUE:
2024 return ("value");
2025 case XML_RELAXNG_LIST:
2026 return ("list");
2027 case XML_RELAXNG_ATTRIBUTE:
2028 return ("attribute");
2029 case XML_RELAXNG_DEF:
2030 return ("def");
2031 case XML_RELAXNG_REF:
2032 return ("ref");
2033 case XML_RELAXNG_EXTERNALREF:
2034 return ("externalRef");
2035 case XML_RELAXNG_PARENTREF:
2036 return ("parentRef");
2037 case XML_RELAXNG_OPTIONAL:
2038 return ("optional");
2039 case XML_RELAXNG_ZEROORMORE:
2040 return ("zeroOrMore");
2041 case XML_RELAXNG_ONEORMORE:
2042 return ("oneOrMore");
2043 case XML_RELAXNG_CHOICE:
2044 return ("choice");
2045 case XML_RELAXNG_GROUP:
2046 return ("group");
2047 case XML_RELAXNG_INTERLEAVE:
2048 return ("interleave");
2049 case XML_RELAXNG_START:
2050 return ("start");
2051 case XML_RELAXNG_NOOP:
2052 return ("noop");
2053 case XML_RELAXNG_PARAM:
2054 return ("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00002055 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002056 return ("unknown");
Daniel Veillard231d7912003-02-09 14:22:17 +00002057}
Daniel Veillardd2298792003-02-14 16:54:11 +00002058
Daniel Veillard6eadf632003-01-23 18:29:16 +00002059/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002060 * xmlRelaxNGGetErrorString:
2061 * @err: the error code
2062 * @arg1: the first string argument
2063 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00002064 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00002065 * computes a formatted error string for the given error code and args
2066 *
2067 * Returns the error string, it must be deallocated by the caller
2068 */
2069static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00002070xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
2071 const xmlChar * arg2)
2072{
Daniel Veillard42f12e92003-03-07 18:32:59 +00002073 char msg[1000];
2074
2075 if (arg1 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002076 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002077 if (arg2 == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002078 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00002079
2080 msg[0] = 0;
2081 switch (err) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002082 case XML_RELAXNG_OK:
2083 return (NULL);
2084 case XML_RELAXNG_ERR_MEMORY:
2085 return (xmlCharStrdup("out of memory\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002086 case XML_RELAXNG_ERR_TYPE:
Daniel Veillard4c004142003-10-07 11:33:24 +00002087 snprintf(msg, 1000, "failed to validate type %s\n", arg1);
2088 break;
2089 case XML_RELAXNG_ERR_TYPEVAL:
2090 snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
2091 arg2);
2092 break;
2093 case XML_RELAXNG_ERR_DUPID:
2094 snprintf(msg, 1000, "ID %s redefined\n", arg1);
2095 break;
2096 case XML_RELAXNG_ERR_TYPECMP:
2097 snprintf(msg, 1000, "failed to compare type %s\n", arg1);
2098 break;
2099 case XML_RELAXNG_ERR_NOSTATE:
2100 return (xmlCharStrdup("Internal error: no state\n"));
2101 case XML_RELAXNG_ERR_NODEFINE:
2102 return (xmlCharStrdup("Internal error: no define\n"));
2103 case XML_RELAXNG_ERR_INTERNAL:
2104 snprintf(msg, 1000, "Internal error: %s\n", arg1);
2105 break;
2106 case XML_RELAXNG_ERR_LISTEXTRA:
2107 snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
2108 break;
2109 case XML_RELAXNG_ERR_INTERNODATA:
2110 return (xmlCharStrdup
2111 ("Internal: interleave block has no data\n"));
2112 case XML_RELAXNG_ERR_INTERSEQ:
2113 return (xmlCharStrdup("Invalid sequence in interleave\n"));
2114 case XML_RELAXNG_ERR_INTEREXTRA:
2115 snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
2116 break;
2117 case XML_RELAXNG_ERR_ELEMNAME:
2118 snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
2119 arg2);
2120 break;
2121 case XML_RELAXNG_ERR_ELEMNONS:
2122 snprintf(msg, 1000, "Expecting a namespace for element %s\n",
2123 arg1);
2124 break;
2125 case XML_RELAXNG_ERR_ELEMWRONGNS:
2126 snprintf(msg, 1000,
2127 "Element %s has wrong namespace: expecting %s\n", arg1,
2128 arg2);
2129 break;
2130 case XML_RELAXNG_ERR_ELEMWRONG:
2131 snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
2132 break;
2133 case XML_RELAXNG_ERR_TEXTWRONG:
2134 snprintf(msg, 1000,
2135 "Did not expect text in element %s content\n", arg1);
2136 break;
2137 case XML_RELAXNG_ERR_ELEMEXTRANS:
2138 snprintf(msg, 1000, "Expecting no namespace for element %s\n",
2139 arg1);
2140 break;
2141 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
2142 snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
2143 break;
2144 case XML_RELAXNG_ERR_NOELEM:
2145 snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
2146 arg1);
2147 break;
2148 case XML_RELAXNG_ERR_NOTELEM:
2149 return (xmlCharStrdup("Expecting an element got text\n"));
2150 case XML_RELAXNG_ERR_ATTRVALID:
2151 snprintf(msg, 1000, "Element %s failed to validate attributes\n",
2152 arg1);
2153 break;
2154 case XML_RELAXNG_ERR_CONTENTVALID:
2155 snprintf(msg, 1000, "Element %s failed to validate content\n",
2156 arg1);
2157 break;
2158 case XML_RELAXNG_ERR_EXTRACONTENT:
2159 snprintf(msg, 1000, "Element %s has extra content: %s\n",
2160 arg1, arg2);
2161 break;
2162 case XML_RELAXNG_ERR_INVALIDATTR:
2163 snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
2164 arg1, arg2);
2165 break;
2166 case XML_RELAXNG_ERR_LACKDATA:
2167 snprintf(msg, 1000, "Datatype element %s contains no data\n",
2168 arg1);
2169 break;
2170 case XML_RELAXNG_ERR_DATAELEM:
2171 snprintf(msg, 1000, "Datatype element %s has child elements\n",
2172 arg1);
2173 break;
2174 case XML_RELAXNG_ERR_VALELEM:
2175 snprintf(msg, 1000, "Value element %s has child elements\n",
2176 arg1);
2177 break;
2178 case XML_RELAXNG_ERR_LISTELEM:
2179 snprintf(msg, 1000, "List element %s has child elements\n",
2180 arg1);
2181 break;
2182 case XML_RELAXNG_ERR_DATATYPE:
2183 snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
2184 break;
2185 case XML_RELAXNG_ERR_VALUE:
2186 snprintf(msg, 1000, "Error validating value %s\n", arg1);
2187 break;
2188 case XML_RELAXNG_ERR_LIST:
2189 return (xmlCharStrdup("Error validating list\n"));
2190 case XML_RELAXNG_ERR_NOGRAMMAR:
2191 return (xmlCharStrdup("No top grammar defined\n"));
2192 case XML_RELAXNG_ERR_EXTRADATA:
2193 return (xmlCharStrdup("Extra data in the document\n"));
2194 default:
2195 return (xmlCharStrdup("Unknown error !\n"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002196 }
2197 if (msg[0] == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002198 snprintf(msg, 1000, "Unknown error code %d\n", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002199 }
Daniel Veillardadbb0e62003-05-10 20:02:45 +00002200 msg[1000 - 1] = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00002201 return (xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00002202}
2203
2204/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002205 * xmlRelaxNGShowValidError:
2206 * @ctxt: the validation context
2207 * @err: the error number
2208 * @node: the node
2209 * @child: the node child generating the problem.
2210 * @arg1: the first argument
2211 * @arg2: the second argument
2212 *
2213 * Show a validation error.
2214 */
2215static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002216xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
2217 xmlRelaxNGValidErr err, xmlNodePtr node,
2218 xmlNodePtr child, const xmlChar * arg1,
2219 const xmlChar * arg2)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002220{
2221 xmlChar *msg;
2222
2223 if (ctxt->error == NULL)
2224 return;
2225
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002226#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002227 xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002228#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002229 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2230 if (msg == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002231 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002232
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002233 if (ctxt->errNo == XML_RELAXNG_OK)
Daniel Veillard4c004142003-10-07 11:33:24 +00002234 ctxt->errNo = err;
2235 xmlRngVErr(ctxt, (child == NULL ? node : child), err,
2236 (const char *) msg, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002237 xmlFree(msg);
2238}
2239
2240/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002241 * xmlRelaxNGPopErrors:
2242 * @ctxt: the validation context
2243 * @level: the error level in the stack
2244 *
2245 * pop and discard all errors until the given level is reached
2246 */
2247static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002248xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
2249{
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002250 int i;
2251 xmlRelaxNGValidErrorPtr err;
2252
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002253#ifdef DEBUG_ERROR
2254 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002255 "Pop errors till level %d\n", level);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002256#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002257 for (i = level; i < ctxt->errNr; i++) {
2258 err = &ctxt->errTab[i];
2259 if (err->flags & ERROR_IS_DUP) {
2260 if (err->arg1 != NULL)
2261 xmlFree((xmlChar *) err->arg1);
2262 err->arg1 = NULL;
2263 if (err->arg2 != NULL)
2264 xmlFree((xmlChar *) err->arg2);
2265 err->arg2 = NULL;
2266 err->flags = 0;
2267 }
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002268 }
2269 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002270 if (ctxt->errNr <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002271 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002272}
Daniel Veillard4c004142003-10-07 11:33:24 +00002273
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002274/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002275 * xmlRelaxNGDumpValidError:
2276 * @ctxt: the validation context
2277 *
2278 * Show all validation error over a given index.
2279 */
2280static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002281xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
2282{
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002283 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002284 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002285
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002286#ifdef DEBUG_ERROR
2287 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00002288 "Dumping error stack %d errors\n", ctxt->errNr);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002289#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002290 for (i = 0, k = 0; i < ctxt->errNr; i++) {
2291 err = &ctxt->errTab[i];
2292 if (k < MAX_ERROR) {
2293 for (j = 0; j < i; j++) {
2294 dup = &ctxt->errTab[j];
2295 if ((err->err == dup->err) && (err->node == dup->node) &&
2296 (xmlStrEqual(err->arg1, dup->arg1)) &&
2297 (xmlStrEqual(err->arg2, dup->arg2))) {
2298 goto skip;
2299 }
2300 }
2301 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2302 err->arg1, err->arg2);
2303 k++;
2304 }
2305 skip:
2306 if (err->flags & ERROR_IS_DUP) {
2307 if (err->arg1 != NULL)
2308 xmlFree((xmlChar *) err->arg1);
2309 err->arg1 = NULL;
2310 if (err->arg2 != NULL)
2311 xmlFree((xmlChar *) err->arg2);
2312 err->arg2 = NULL;
2313 err->flags = 0;
2314 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002315 }
2316 ctxt->errNr = 0;
2317}
Daniel Veillard4c004142003-10-07 11:33:24 +00002318
Daniel Veillard42f12e92003-03-07 18:32:59 +00002319/**
2320 * xmlRelaxNGAddValidError:
2321 * @ctxt: the validation context
2322 * @err: the error number
2323 * @arg1: the first argument
2324 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002325 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002326 *
2327 * Register a validation error, either generating it if it's sure
2328 * or stacking it for later handling if unsure.
2329 */
2330static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002331xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
2332 xmlRelaxNGValidErr err, const xmlChar * arg1,
2333 const xmlChar * arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002334{
2335 if ((ctxt == NULL) || (ctxt->error == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002336 return;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002337
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002338#ifdef DEBUG_ERROR
Daniel Veillard4c004142003-10-07 11:33:24 +00002339 xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002340#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002341 /*
2342 * generate the error directly
2343 */
William M. Brack60929622004-03-27 17:54:18 +00002344 if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
2345 (ctxt->flags & FLAGS_NEGATIVE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002346 xmlNodePtr node, seq;
2347
2348 /*
2349 * Flush first any stacked error which might be the
2350 * real cause of the problem.
2351 */
2352 if (ctxt->errNr != 0)
2353 xmlRelaxNGDumpValidError(ctxt);
2354 if (ctxt->state != NULL) {
2355 node = ctxt->state->node;
2356 seq = ctxt->state->seq;
2357 } else {
2358 node = seq = NULL;
2359 }
2360 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002361 }
2362 /*
2363 * Stack the error for later processing if needed
2364 */
2365 else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002366 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002367 }
2368}
2369
Daniel Veillard6eadf632003-01-23 18:29:16 +00002370
2371/************************************************************************
2372 * *
2373 * Type library hooks *
2374 * *
2375 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002376static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00002377 const xmlChar * str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002378
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002379/**
2380 * xmlRelaxNGSchemaTypeHave:
2381 * @data: data needed for the library
2382 * @type: the type name
2383 *
2384 * Check if the given type is provided by
2385 * the W3C XMLSchema Datatype library.
2386 *
2387 * Returns 1 if yes, 0 if no and -1 in case of error.
2388 */
2389static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002390xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
2391{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002392 xmlSchemaTypePtr typ;
2393
2394 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002395 return (-1);
2396 typ = xmlSchemaGetPredefinedType(type,
2397 BAD_CAST
2398 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002399 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002400 return (0);
2401 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002402}
2403
2404/**
2405 * xmlRelaxNGSchemaTypeCheck:
2406 * @data: data needed for the library
2407 * @type: the type name
2408 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002409 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002410 *
2411 * Check if the given type and value are validated by
2412 * the W3C XMLSchema Datatype library.
2413 *
2414 * Returns 1 if yes, 0 if no and -1 in case of error.
2415 */
2416static int
2417xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002418 const xmlChar * type,
2419 const xmlChar * value,
2420 void **result, xmlNodePtr node)
2421{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002422 xmlSchemaTypePtr typ;
2423 int ret;
2424
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002425 if ((type == NULL) || (value == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002426 return (-1);
2427 typ = xmlSchemaGetPredefinedType(type,
2428 BAD_CAST
2429 "http://www.w3.org/2001/XMLSchema");
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002430 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002431 return (-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002432 ret = xmlSchemaValPredefTypeNode(typ, value,
Daniel Veillard4c004142003-10-07 11:33:24 +00002433 (xmlSchemaValPtr *) result, node);
2434 if (ret == 2) /* special ID error code */
2435 return (2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002436 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002437 return (1);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002438 if (ret > 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002439 return (0);
2440 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002441}
2442
2443/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002444 * xmlRelaxNGSchemaFacetCheck:
2445 * @data: data needed for the library
2446 * @type: the type name
2447 * @facet: the facet name
2448 * @val: the facet value
2449 * @strval: the string value
2450 * @value: the value to check
2451 *
2452 * Function provided by a type library to check a value facet
2453 *
2454 * Returns 1 if yes, 0 if no and -1 in case of error.
2455 */
2456static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002457xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
2458 const xmlChar * type, const xmlChar * facetname,
2459 const xmlChar * val, const xmlChar * strval,
2460 void *value)
2461{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002462 xmlSchemaFacetPtr facet;
2463 xmlSchemaTypePtr typ;
2464 int ret;
2465
2466 if ((type == NULL) || (strval == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002467 return (-1);
2468 typ = xmlSchemaGetPredefinedType(type,
2469 BAD_CAST
2470 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002471 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002472 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002473
2474 facet = xmlSchemaNewFacet();
2475 if (facet == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002476 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002477
Daniel Veillard4c004142003-10-07 11:33:24 +00002478 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002479 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002480 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002481 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002482 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002483 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002484 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002485 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002486 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002487 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002488 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002489 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
Daniel Veillard4c004142003-10-07 11:33:24 +00002490 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002491 facet->type = XML_SCHEMA_FACET_PATTERN;
Daniel Veillard4c004142003-10-07 11:33:24 +00002492 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002493 facet->type = XML_SCHEMA_FACET_ENUMERATION;
Daniel Veillard4c004142003-10-07 11:33:24 +00002494 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002495 facet->type = XML_SCHEMA_FACET_WHITESPACE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002496 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002497 facet->type = XML_SCHEMA_FACET_LENGTH;
Daniel Veillard4c004142003-10-07 11:33:24 +00002498 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002499 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2500 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2501 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2502 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002503 xmlSchemaFreeFacet(facet);
2504 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002505 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00002506 facet->value = val;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002507 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2508 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002509 xmlSchemaFreeFacet(facet);
2510 return (-1);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002511 }
2512 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2513 xmlSchemaFreeFacet(facet);
2514 if (ret != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002515 return (-1);
2516 return (0);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002517}
2518
2519/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002520 * xmlRelaxNGSchemaFreeValue:
2521 * @data: data needed for the library
2522 * @value: the value to free
2523 *
2524 * Function provided by a type library to free a Schemas value
2525 *
2526 * Returns 1 if yes, 0 if no and -1 in case of error.
2527 */
2528static void
Daniel Veillard4c004142003-10-07 11:33:24 +00002529xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
2530{
Daniel Veillard80b19092003-03-28 13:29:53 +00002531 xmlSchemaFreeValue(value);
2532}
2533
2534/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002535 * xmlRelaxNGSchemaTypeCompare:
2536 * @data: data needed for the library
2537 * @type: the type name
2538 * @value1: the first value
2539 * @value2: the second value
2540 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002541 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002542 * Datatype library.
2543 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002544 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002545 */
2546static int
2547xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002548 const xmlChar * type,
2549 const xmlChar * value1,
2550 xmlNodePtr ctxt1,
2551 void *comp1,
2552 const xmlChar * value2, xmlNodePtr ctxt2)
2553{
Daniel Veillard80b19092003-03-28 13:29:53 +00002554 int ret;
2555 xmlSchemaTypePtr typ;
2556 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2557
2558 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00002559 return (-1);
2560 typ = xmlSchemaGetPredefinedType(type,
2561 BAD_CAST
2562 "http://www.w3.org/2001/XMLSchema");
Daniel Veillard80b19092003-03-28 13:29:53 +00002563 if (typ == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002564 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002565 if (comp1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002566 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2567 if (ret != 0)
2568 return (-1);
2569 if (res1 == NULL)
2570 return (-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002571 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002572 res1 = (xmlSchemaValPtr) comp1;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002573 }
2574 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002575 if (ret != 0) {
Daniel Veillardf4644032005-06-13 11:41:31 +00002576 if ((comp1 == NULL) && (res1 != NULL))
2577 xmlSchemaFreeValue(res1);
Daniel Veillard4c004142003-10-07 11:33:24 +00002578 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002579 }
2580 if (res1 == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002581 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002582 }
2583 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002584 if (res1 != (xmlSchemaValPtr) comp1)
Daniel Veillard4c004142003-10-07 11:33:24 +00002585 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002586 xmlSchemaFreeValue(res2);
2587 if (ret == -2)
Daniel Veillard4c004142003-10-07 11:33:24 +00002588 return (-1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002589 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002590 return (1);
2591 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002592}
Daniel Veillard4c004142003-10-07 11:33:24 +00002593
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002594/**
2595 * xmlRelaxNGDefaultTypeHave:
2596 * @data: data needed for the library
2597 * @type: the type name
2598 *
2599 * Check if the given type is provided by
2600 * the default datatype library.
2601 *
2602 * Returns 1 if yes, 0 if no and -1 in case of error.
2603 */
2604static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002605xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
2606 const xmlChar * type)
2607{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002608 if (type == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002609 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002610 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002611 return (1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002612 if (xmlStrEqual(type, BAD_CAST "token"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002613 return (1);
2614 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002615}
2616
2617/**
2618 * xmlRelaxNGDefaultTypeCheck:
2619 * @data: data needed for the library
2620 * @type: the type name
2621 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002622 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002623 *
2624 * Check if the given type and value are validated by
2625 * the default datatype library.
2626 *
2627 * Returns 1 if yes, 0 if no and -1 in case of error.
2628 */
2629static int
2630xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002631 const xmlChar * type ATTRIBUTE_UNUSED,
2632 const xmlChar * value ATTRIBUTE_UNUSED,
2633 void **result ATTRIBUTE_UNUSED,
2634 xmlNodePtr node ATTRIBUTE_UNUSED)
2635{
Daniel Veillardd4310742003-02-18 21:12:46 +00002636 if (value == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002637 return (-1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002638 if (xmlStrEqual(type, BAD_CAST "string"))
Daniel Veillard4c004142003-10-07 11:33:24 +00002639 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002640 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002641 return (1);
Daniel Veillardd4310742003-02-18 21:12:46 +00002642 }
2643
Daniel Veillard4c004142003-10-07 11:33:24 +00002644 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002645}
2646
2647/**
2648 * xmlRelaxNGDefaultTypeCompare:
2649 * @data: data needed for the library
2650 * @type: the type name
2651 * @value1: the first value
2652 * @value2: the second value
2653 *
2654 * Compare two values accordingly a type from the default
2655 * datatype library.
2656 *
2657 * Returns 1 if yes, 0 if no and -1 in case of error.
2658 */
2659static int
2660xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00002661 const xmlChar * type,
2662 const xmlChar * value1,
2663 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2664 void *comp1 ATTRIBUTE_UNUSED,
2665 const xmlChar * value2,
2666 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
2667{
Daniel Veillardea3f3982003-01-26 19:45:18 +00002668 int ret = -1;
2669
2670 if (xmlStrEqual(type, BAD_CAST "string")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002671 ret = xmlStrEqual(value1, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002672 } else if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002673 if (!xmlStrEqual(value1, value2)) {
2674 xmlChar *nval, *nvalue;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002675
Daniel Veillard4c004142003-10-07 11:33:24 +00002676 /*
2677 * TODO: trivial optimizations are possible by
2678 * computing at compile-time
2679 */
2680 nval = xmlRelaxNGNormalize(NULL, value1);
2681 nvalue = xmlRelaxNGNormalize(NULL, value2);
Daniel Veillardea3f3982003-01-26 19:45:18 +00002682
Daniel Veillard4c004142003-10-07 11:33:24 +00002683 if ((nval == NULL) || (nvalue == NULL))
2684 ret = -1;
2685 else if (xmlStrEqual(nval, nvalue))
2686 ret = 1;
2687 else
2688 ret = 0;
2689 if (nval != NULL)
2690 xmlFree(nval);
2691 if (nvalue != NULL)
2692 xmlFree(nvalue);
2693 } else
2694 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002695 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002696 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002697}
Daniel Veillard4c004142003-10-07 11:33:24 +00002698
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002699static int xmlRelaxNGTypeInitialized = 0;
2700static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2701
2702/**
2703 * xmlRelaxNGFreeTypeLibrary:
2704 * @lib: the type library structure
2705 * @namespace: the URI bound to the library
2706 *
2707 * Free the structure associated to the type library
2708 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002709static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002710xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
Daniel Veillard4c004142003-10-07 11:33:24 +00002711 const xmlChar * namespace ATTRIBUTE_UNUSED)
2712{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002713 if (lib == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002714 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002715 if (lib->namespace != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00002716 xmlFree((xmlChar *) lib->namespace);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002717 xmlFree(lib);
2718}
2719
2720/**
2721 * xmlRelaxNGRegisterTypeLibrary:
2722 * @namespace: the URI bound to the library
2723 * @data: data associated to the library
2724 * @have: the provide function
2725 * @check: the checking function
2726 * @comp: the comparison function
2727 *
2728 * Register a new type library
2729 *
2730 * Returns 0 in case of success and -1 in case of error.
2731 */
2732static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002733xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
2734 xmlRelaxNGTypeHave have,
2735 xmlRelaxNGTypeCheck check,
2736 xmlRelaxNGTypeCompare comp,
2737 xmlRelaxNGFacetCheck facet,
2738 xmlRelaxNGTypeFree freef)
2739{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002740 xmlRelaxNGTypeLibraryPtr lib;
2741 int ret;
2742
2743 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00002744 (check == NULL) || (comp == NULL))
2745 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002746 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002747 xmlGenericError(xmlGenericErrorContext,
2748 "Relax-NG types library '%s' already registered\n",
2749 namespace);
2750 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002751 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002752 lib =
2753 (xmlRelaxNGTypeLibraryPtr)
2754 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002755 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002756 xmlRngVErrMemory(NULL, "adding types library\n");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002757 return (-1);
2758 }
2759 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2760 lib->namespace = xmlStrdup(namespace);
2761 lib->data = data;
2762 lib->have = have;
2763 lib->comp = comp;
2764 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002765 lib->facet = facet;
2766 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002767 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2768 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002769 xmlGenericError(xmlGenericErrorContext,
2770 "Relax-NG types library failed to register '%s'\n",
2771 namespace);
2772 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2773 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002774 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002775 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002776}
2777
2778/**
2779 * xmlRelaxNGInitTypes:
2780 *
2781 * Initilize the default type libraries.
2782 *
2783 * Returns 0 in case of success and -1 in case of error.
2784 */
Daniel Veillarddd6d3002004-11-03 14:20:29 +00002785int
Daniel Veillard4c004142003-10-07 11:33:24 +00002786xmlRelaxNGInitTypes(void)
2787{
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002788 if (xmlRelaxNGTypeInitialized != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002789 return (0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002790 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2791 if (xmlRelaxNGRegisteredTypes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002792 xmlGenericError(xmlGenericErrorContext,
2793 "Failed to allocate sh table for Relax-NG types\n");
2794 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002795 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002796 xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2797 "http://www.w3.org/2001/XMLSchema-datatypes",
2798 NULL, xmlRelaxNGSchemaTypeHave,
2799 xmlRelaxNGSchemaTypeCheck,
2800 xmlRelaxNGSchemaTypeCompare,
2801 xmlRelaxNGSchemaFacetCheck,
2802 xmlRelaxNGSchemaFreeValue);
2803 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
2804 xmlRelaxNGDefaultTypeHave,
2805 xmlRelaxNGDefaultTypeCheck,
2806 xmlRelaxNGDefaultTypeCompare, NULL,
2807 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002808 xmlRelaxNGTypeInitialized = 1;
Daniel Veillard4c004142003-10-07 11:33:24 +00002809 return (0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002810}
2811
2812/**
2813 * xmlRelaxNGCleanupTypes:
2814 *
2815 * Cleanup the default Schemas type library associated to RelaxNG
2816 */
Daniel Veillard4c004142003-10-07 11:33:24 +00002817void
2818xmlRelaxNGCleanupTypes(void)
2819{
Daniel Veillarda84c0b32003-06-02 16:58:46 +00002820 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002821 if (xmlRelaxNGTypeInitialized == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00002822 return;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002823 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
Daniel Veillard4c004142003-10-07 11:33:24 +00002824 xmlRelaxNGFreeTypeLibrary);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002825 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002826}
2827
2828/************************************************************************
2829 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002830 * Compiling element content into regexp *
2831 * *
2832 * Sometime the element content can be compiled into a pure regexp, *
2833 * This allows a faster execution and streamability at that level *
2834 * *
2835 ************************************************************************/
2836
Daniel Veillard52b48c72003-04-13 19:53:42 +00002837static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2838 xmlRelaxNGDefinePtr def);
2839
Daniel Veillard952379b2003-03-17 15:37:12 +00002840/**
2841 * xmlRelaxNGIsCompileable:
2842 * @define: the definition to check
2843 *
2844 * Check if a definition is nullable.
2845 *
2846 * Returns 1 if yes, 0 if no and -1 in case of error
2847 */
2848static int
Daniel Veillard4c004142003-10-07 11:33:24 +00002849xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def)
2850{
Daniel Veillard52b48c72003-04-13 19:53:42 +00002851 int ret = -1;
2852
Daniel Veillard952379b2003-03-17 15:37:12 +00002853 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002854 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00002855 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002856 if ((def->type != XML_RELAXNG_ELEMENT) &&
2857 (def->dflags & IS_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002858 return (1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002859 if ((def->type != XML_RELAXNG_ELEMENT) &&
2860 (def->dflags & IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002861 return (0);
2862 switch (def->type) {
Daniel Veillard952379b2003-03-17 15:37:12 +00002863 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002864 ret = xmlRelaxNGIsCompileable(def->content);
2865 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002866 case XML_RELAXNG_TEXT:
Daniel Veillard952379b2003-03-17 15:37:12 +00002867 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00002868 ret = 1;
2869 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002870 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00002871 /*
2872 * Check if the element content is compileable
2873 */
2874 if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2875 ((def->dflags & IS_COMPILABLE) == 0)) {
2876 xmlRelaxNGDefinePtr list;
2877
2878 list = def->content;
2879 while (list != NULL) {
2880 ret = xmlRelaxNGIsCompileable(list);
2881 if (ret != 1)
2882 break;
2883 list = list->next;
2884 }
William M. Brack60929622004-03-27 17:54:18 +00002885 /*
2886 * Because the routine is recursive, we must guard against
2887 * discovering both COMPILABLE and NOT_COMPILABLE
2888 */
2889 if (ret == 0) {
2890 def->dflags &= ~IS_COMPILABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +00002891 def->dflags |= IS_NOT_COMPILABLE;
William M. Brack60929622004-03-27 17:54:18 +00002892 }
2893 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
Daniel Veillard4c004142003-10-07 11:33:24 +00002894 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002895#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00002896 if (ret == 1) {
2897 xmlGenericError(xmlGenericErrorContext,
2898 "element content for %s is compilable\n",
2899 def->name);
2900 } else if (ret == 0) {
2901 xmlGenericError(xmlGenericErrorContext,
2902 "element content for %s is not compilable\n",
2903 def->name);
2904 } else {
2905 xmlGenericError(xmlGenericErrorContext,
2906 "Problem in RelaxNGIsCompileable for element %s\n",
2907 def->name);
2908 }
Daniel Veillardd94849b2003-07-28 13:02:24 +00002909#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002910 }
2911 /*
2912 * All elements return a compileable status unless they
2913 * are generic like anyName
2914 */
2915 if ((def->nameClass != NULL) || (def->name == NULL))
2916 ret = 0;
2917 else
2918 ret = 1;
2919 return (ret);
Daniel Veillard2134ab12003-07-23 19:56:29 +00002920 case XML_RELAXNG_REF:
2921 case XML_RELAXNG_EXTERNALREF:
2922 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00002923 if (def->depth == -20) {
2924 return (1);
2925 } else {
2926 xmlRelaxNGDefinePtr list;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002927
Daniel Veillard4c004142003-10-07 11:33:24 +00002928 def->depth = -20;
2929 list = def->content;
2930 while (list != NULL) {
2931 ret = xmlRelaxNGIsCompileable(list);
2932 if (ret != 1)
2933 break;
2934 list = list->next;
2935 }
2936 }
2937 break;
Daniel Veillard2134ab12003-07-23 19:56:29 +00002938 case XML_RELAXNG_START:
Daniel Veillard952379b2003-03-17 15:37:12 +00002939 case XML_RELAXNG_OPTIONAL:
2940 case XML_RELAXNG_ZEROORMORE:
2941 case XML_RELAXNG_ONEORMORE:
2942 case XML_RELAXNG_CHOICE:
2943 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00002944 case XML_RELAXNG_DEF:{
2945 xmlRelaxNGDefinePtr list;
Daniel Veillard952379b2003-03-17 15:37:12 +00002946
Daniel Veillard4c004142003-10-07 11:33:24 +00002947 list = def->content;
2948 while (list != NULL) {
2949 ret = xmlRelaxNGIsCompileable(list);
2950 if (ret != 1)
2951 break;
2952 list = list->next;
2953 }
2954 break;
2955 }
Daniel Veillard952379b2003-03-17 15:37:12 +00002956 case XML_RELAXNG_EXCEPT:
2957 case XML_RELAXNG_ATTRIBUTE:
2958 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002959 case XML_RELAXNG_DATATYPE:
2960 case XML_RELAXNG_LIST:
2961 case XML_RELAXNG_PARAM:
2962 case XML_RELAXNG_VALUE:
Daniel Veillard952379b2003-03-17 15:37:12 +00002963 case XML_RELAXNG_NOT_ALLOWED:
William M. Brack7e29c0a2004-04-02 09:07:22 +00002964 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00002965 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002966 }
Daniel Veillard4c004142003-10-07 11:33:24 +00002967 if (ret == 0)
2968 def->dflags |= IS_NOT_COMPILABLE;
2969 if (ret == 1)
2970 def->dflags |= IS_COMPILABLE;
Daniel Veillardd94849b2003-07-28 13:02:24 +00002971#ifdef DEBUG_COMPILE
2972 if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002973 xmlGenericError(xmlGenericErrorContext,
2974 "RelaxNGIsCompileable %s : true\n",
2975 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002976 } else if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00002977 xmlGenericError(xmlGenericErrorContext,
2978 "RelaxNGIsCompileable %s : false\n",
2979 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002980 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00002981 xmlGenericError(xmlGenericErrorContext,
2982 "Problem in RelaxNGIsCompileable %s\n",
2983 xmlRelaxNGDefName(def));
Daniel Veillardd94849b2003-07-28 13:02:24 +00002984 }
2985#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00002986 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002987}
2988
2989/**
2990 * xmlRelaxNGCompile:
2991 * ctxt: the RelaxNG parser context
2992 * @define: the definition tree to compile
2993 *
2994 * Compile the set of definitions, it works recursively, till the
2995 * element boundaries, where it tries to compile the content if possible
2996 *
2997 * Returns 0 if success and -1 in case of error
2998 */
2999static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003000xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3001{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003002 int ret = 0;
3003 xmlRelaxNGDefinePtr list;
3004
Daniel Veillard4c004142003-10-07 11:33:24 +00003005 if ((ctxt == NULL) || (def == NULL))
3006 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003007
Daniel Veillard4c004142003-10-07 11:33:24 +00003008 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003009 case XML_RELAXNG_START:
3010 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003011 xmlAutomataPtr oldam = ctxt->am;
3012 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003013
3014 def->depth = -25;
3015
Daniel Veillard4c004142003-10-07 11:33:24 +00003016 list = def->content;
3017 ctxt->am = xmlNewAutomata();
3018 if (ctxt->am == NULL)
3019 return (-1);
3020 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3021 while (list != NULL) {
3022 xmlRelaxNGCompile(ctxt, list);
3023 list = list->next;
3024 }
3025 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3026 def->contModel = xmlAutomataCompile(ctxt->am);
3027 xmlRegexpIsDeterminist(def->contModel);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003028
Daniel Veillard4c004142003-10-07 11:33:24 +00003029 xmlFreeAutomata(ctxt->am);
3030 ctxt->state = oldstate;
3031 ctxt->am = oldam;
3032 }
3033 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003034 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003035 if ((ctxt->am != NULL) && (def->name != NULL)) {
3036 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
3037 ctxt->state, NULL,
3038 def->name, def->ns,
3039 def);
3040 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003041 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003042 xmlAutomataPtr oldam = ctxt->am;
3043 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003044
3045 def->depth = -25;
3046
Daniel Veillard4c004142003-10-07 11:33:24 +00003047 list = def->content;
3048 ctxt->am = xmlNewAutomata();
3049 if (ctxt->am == NULL)
3050 return (-1);
3051 ctxt->state = xmlAutomataGetInitState(ctxt->am);
3052 while (list != NULL) {
3053 xmlRelaxNGCompile(ctxt, list);
3054 list = list->next;
3055 }
3056 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3057 def->contModel = xmlAutomataCompile(ctxt->am);
3058 if (!xmlRegexpIsDeterminist(def->contModel)) {
3059 /*
3060 * we can only use the automata if it is determinist
3061 */
3062 xmlRegFreeRegexp(def->contModel);
3063 def->contModel = NULL;
3064 }
3065 xmlFreeAutomata(ctxt->am);
3066 ctxt->state = oldstate;
3067 ctxt->am = oldam;
3068 } else {
3069 xmlAutomataPtr oldam = ctxt->am;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003070
Daniel Veillard4c004142003-10-07 11:33:24 +00003071 /*
3072 * we can't build the content model for this element content
3073 * but it still might be possible to build it for some of its
3074 * children, recurse.
3075 */
3076 ret = xmlRelaxNGTryCompile(ctxt, def);
3077 ctxt->am = oldam;
3078 }
3079 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003080 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003081 ret = xmlRelaxNGCompile(ctxt, def->content);
3082 break;
3083 case XML_RELAXNG_OPTIONAL:{
3084 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003085
Daniel Veillard4c004142003-10-07 11:33:24 +00003086 xmlRelaxNGCompile(ctxt, def->content);
3087 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3088 break;
3089 }
3090 case XML_RELAXNG_ZEROORMORE:{
3091 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003092
Daniel Veillard4c004142003-10-07 11:33:24 +00003093 ctxt->state =
3094 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3095 oldstate = ctxt->state;
3096 list = def->content;
3097 while (list != NULL) {
3098 xmlRelaxNGCompile(ctxt, list);
3099 list = list->next;
3100 }
3101 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3102 ctxt->state =
3103 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3104 break;
3105 }
3106 case XML_RELAXNG_ONEORMORE:{
3107 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003108
Daniel Veillard4c004142003-10-07 11:33:24 +00003109 list = def->content;
3110 while (list != NULL) {
3111 xmlRelaxNGCompile(ctxt, list);
3112 list = list->next;
3113 }
3114 oldstate = ctxt->state;
3115 list = def->content;
3116 while (list != NULL) {
3117 xmlRelaxNGCompile(ctxt, list);
3118 list = list->next;
3119 }
3120 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3121 ctxt->state =
3122 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3123 break;
3124 }
3125 case XML_RELAXNG_CHOICE:{
3126 xmlAutomataStatePtr target = NULL;
3127 xmlAutomataStatePtr oldstate = ctxt->state;
3128
3129 list = def->content;
3130 while (list != NULL) {
3131 ctxt->state = oldstate;
3132 ret = xmlRelaxNGCompile(ctxt, list);
3133 if (ret != 0)
3134 break;
3135 if (target == NULL)
3136 target = ctxt->state;
3137 else {
3138 xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3139 target);
3140 }
3141 list = list->next;
3142 }
3143 ctxt->state = target;
3144
3145 break;
3146 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003147 case XML_RELAXNG_REF:
3148 case XML_RELAXNG_EXTERNALREF:
3149 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00003150 case XML_RELAXNG_GROUP:
3151 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003152 list = def->content;
3153 while (list != NULL) {
3154 ret = xmlRelaxNGCompile(ctxt, list);
3155 if (ret != 0)
3156 break;
3157 list = list->next;
3158 }
3159 break;
3160 case XML_RELAXNG_TEXT:{
3161 xmlAutomataStatePtr oldstate;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003162
Daniel Veillard4c004142003-10-07 11:33:24 +00003163 ctxt->state =
3164 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3165 oldstate = ctxt->state;
3166 xmlRelaxNGCompile(ctxt, def->content);
3167 xmlAutomataNewTransition(ctxt->am, ctxt->state,
3168 ctxt->state, BAD_CAST "#text",
3169 NULL);
3170 ctxt->state =
3171 xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3172 break;
3173 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003174 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00003175 ctxt->state =
3176 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3177 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003178 case XML_RELAXNG_EXCEPT:
3179 case XML_RELAXNG_ATTRIBUTE:
3180 case XML_RELAXNG_INTERLEAVE:
3181 case XML_RELAXNG_NOT_ALLOWED:
3182 case XML_RELAXNG_DATATYPE:
3183 case XML_RELAXNG_LIST:
3184 case XML_RELAXNG_PARAM:
3185 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003186 /* This should not happen and generate an internal error */
3187 fprintf(stderr, "RNG internal error trying to compile %s\n",
3188 xmlRelaxNGDefName(def));
3189 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003190 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003191 return (ret);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003192}
3193
3194/**
3195 * xmlRelaxNGTryCompile:
3196 * ctxt: the RelaxNG parser context
3197 * @define: the definition tree to compile
3198 *
3199 * Try to compile the set of definitions, it works recursively,
3200 * possibly ignoring parts which cannot be compiled.
3201 *
3202 * Returns 0 if success and -1 in case of error
3203 */
3204static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003205xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3206{
Daniel Veillard52b48c72003-04-13 19:53:42 +00003207 int ret = 0;
3208 xmlRelaxNGDefinePtr list;
3209
Daniel Veillard4c004142003-10-07 11:33:24 +00003210 if ((ctxt == NULL) || (def == NULL))
3211 return (-1);
Daniel Veillard52b48c72003-04-13 19:53:42 +00003212
3213 if ((def->type == XML_RELAXNG_START) ||
3214 (def->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003215 ret = xmlRelaxNGIsCompileable(def);
3216 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3217 ctxt->am = NULL;
3218 ret = xmlRelaxNGCompile(ctxt, def);
Daniel Veillard2134ab12003-07-23 19:56:29 +00003219#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00003220 if (ret == 0) {
3221 if (def->type == XML_RELAXNG_START)
3222 xmlGenericError(xmlGenericErrorContext,
3223 "compiled the start\n");
3224 else
3225 xmlGenericError(xmlGenericErrorContext,
3226 "compiled element %s\n", def->name);
3227 } else {
3228 if (def->type == XML_RELAXNG_START)
3229 xmlGenericError(xmlGenericErrorContext,
3230 "failed to compile the start\n");
3231 else
3232 xmlGenericError(xmlGenericErrorContext,
3233 "failed to compile element %s\n",
3234 def->name);
3235 }
Daniel Veillard2134ab12003-07-23 19:56:29 +00003236#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00003237 return (ret);
3238 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00003239 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003240 switch (def->type) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00003241 case XML_RELAXNG_NOOP:
Daniel Veillard4c004142003-10-07 11:33:24 +00003242 ret = xmlRelaxNGTryCompile(ctxt, def->content);
3243 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003244 case XML_RELAXNG_TEXT:
3245 case XML_RELAXNG_DATATYPE:
3246 case XML_RELAXNG_LIST:
3247 case XML_RELAXNG_PARAM:
3248 case XML_RELAXNG_VALUE:
3249 case XML_RELAXNG_EMPTY:
3250 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003251 ret = 0;
3252 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003253 case XML_RELAXNG_OPTIONAL:
3254 case XML_RELAXNG_ZEROORMORE:
3255 case XML_RELAXNG_ONEORMORE:
3256 case XML_RELAXNG_CHOICE:
3257 case XML_RELAXNG_GROUP:
3258 case XML_RELAXNG_DEF:
Daniel Veillard2134ab12003-07-23 19:56:29 +00003259 case XML_RELAXNG_START:
3260 case XML_RELAXNG_REF:
3261 case XML_RELAXNG_EXTERNALREF:
3262 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00003263 list = def->content;
3264 while (list != NULL) {
3265 ret = xmlRelaxNGTryCompile(ctxt, list);
3266 if (ret != 0)
3267 break;
3268 list = list->next;
3269 }
3270 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003271 case XML_RELAXNG_EXCEPT:
3272 case XML_RELAXNG_ATTRIBUTE:
3273 case XML_RELAXNG_INTERLEAVE:
3274 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00003275 ret = 0;
3276 break;
Daniel Veillard52b48c72003-04-13 19:53:42 +00003277 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003278 return (ret);
Daniel Veillard952379b2003-03-17 15:37:12 +00003279}
3280
3281/************************************************************************
3282 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00003283 * Parsing functions *
3284 * *
3285 ************************************************************************/
3286
Daniel Veillard4c004142003-10-07 11:33:24 +00003287static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3288 ctxt, xmlNodePtr node);
3289static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3290 ctxt, xmlNodePtr node);
3291static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3292 ctxt, xmlNodePtr nodes,
3293 int group);
3294static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3295 ctxt, xmlNodePtr node);
3296static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3297 xmlNodePtr node);
3298static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3299 xmlNodePtr nodes);
3300static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3301 ctxt, xmlNodePtr node,
3302 xmlRelaxNGDefinePtr
3303 def);
3304static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3305 ctxt, xmlNodePtr nodes);
3306static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3307 xmlRelaxNGDefinePtr define,
3308 xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003309
3310
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003311#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00003312
3313/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003314 * xmlRelaxNGIsNullable:
3315 * @define: the definition to verify
3316 *
3317 * Check if a definition is nullable.
3318 *
3319 * Returns 1 if yes, 0 if no and -1 in case of error
3320 */
3321static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003322xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3323{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003324 int ret;
Daniel Veillard4c004142003-10-07 11:33:24 +00003325
Daniel Veillardfd573f12003-03-16 17:52:32 +00003326 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003327 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003328
Daniel Veillarde063f482003-03-21 16:53:17 +00003329 if (define->dflags & IS_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003330 return (1);
Daniel Veillarde063f482003-03-21 16:53:17 +00003331 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillard4c004142003-10-07 11:33:24 +00003332 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003333 switch (define->type) {
3334 case XML_RELAXNG_EMPTY:
3335 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00003336 ret = 1;
3337 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003338 case XML_RELAXNG_NOOP:
3339 case XML_RELAXNG_DEF:
3340 case XML_RELAXNG_REF:
3341 case XML_RELAXNG_EXTERNALREF:
3342 case XML_RELAXNG_PARENTREF:
3343 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003344 ret = xmlRelaxNGIsNullable(define->content);
3345 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003346 case XML_RELAXNG_EXCEPT:
3347 case XML_RELAXNG_NOT_ALLOWED:
3348 case XML_RELAXNG_ELEMENT:
3349 case XML_RELAXNG_DATATYPE:
3350 case XML_RELAXNG_PARAM:
3351 case XML_RELAXNG_VALUE:
3352 case XML_RELAXNG_LIST:
3353 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003354 ret = 0;
3355 break;
3356 case XML_RELAXNG_CHOICE:{
3357 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003358
Daniel Veillard4c004142003-10-07 11:33:24 +00003359 while (list != NULL) {
3360 ret = xmlRelaxNGIsNullable(list);
3361 if (ret != 0)
3362 goto done;
3363 list = list->next;
3364 }
3365 ret = 0;
3366 break;
3367 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003368 case XML_RELAXNG_START:
3369 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00003370 case XML_RELAXNG_GROUP:{
3371 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003372
Daniel Veillard4c004142003-10-07 11:33:24 +00003373 while (list != NULL) {
3374 ret = xmlRelaxNGIsNullable(list);
3375 if (ret != 1)
3376 goto done;
3377 list = list->next;
3378 }
3379 return (1);
3380 }
3381 default:
3382 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003383 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003384 done:
Daniel Veillardfd573f12003-03-16 17:52:32 +00003385 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003386 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003387 if (ret == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00003388 define->dflags |= IS_NULLABLE;
3389 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003390}
3391
3392/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003393 * xmlRelaxNGIsBlank:
3394 * @str: a string
3395 *
3396 * Check if a string is ignorable c.f. 4.2. Whitespace
3397 *
3398 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3399 */
3400static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003401xmlRelaxNGIsBlank(xmlChar * str)
3402{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003403 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003404 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003405 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00003406 if (!(IS_BLANK_CH(*str)))
Daniel Veillard4c004142003-10-07 11:33:24 +00003407 return (0);
3408 str++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003409 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003410 return (1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003411}
3412
Daniel Veillard6eadf632003-01-23 18:29:16 +00003413/**
3414 * xmlRelaxNGGetDataTypeLibrary:
3415 * @ctxt: a Relax-NG parser context
3416 * @node: the current data or value element
3417 *
3418 * Applies algorithm from 4.3. datatypeLibrary attribute
3419 *
3420 * Returns the datatypeLibary value or NULL if not found
3421 */
3422static xmlChar *
3423xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00003424 xmlNodePtr node)
3425{
Daniel Veillard6eadf632003-01-23 18:29:16 +00003426 xmlChar *ret, *escape;
3427
Daniel Veillard6eadf632003-01-23 18:29:16 +00003428 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003429 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3430 if (ret != NULL) {
3431 if (ret[0] == 0) {
3432 xmlFree(ret);
3433 return (NULL);
3434 }
3435 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3436 if (escape == NULL) {
3437 return (ret);
3438 }
3439 xmlFree(ret);
3440 return (escape);
3441 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00003442 }
3443 node = node->parent;
3444 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003445 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3446 if (ret != NULL) {
3447 if (ret[0] == 0) {
3448 xmlFree(ret);
3449 return (NULL);
3450 }
3451 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3452 if (escape == NULL) {
3453 return (ret);
3454 }
3455 xmlFree(ret);
3456 return (escape);
3457 }
3458 node = node->parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00003459 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003460 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003461}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003462
3463/**
Daniel Veillardedc91922003-01-26 00:52:04 +00003464 * xmlRelaxNGParseValue:
3465 * @ctxt: a Relax-NG parser context
3466 * @node: the data node.
3467 *
3468 * parse the content of a RelaxNG value node.
3469 *
3470 * Returns the definition pointer or NULL in case of error
3471 */
3472static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003473xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3474{
Daniel Veillardedc91922003-01-26 00:52:04 +00003475 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00003476 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00003477 xmlChar *type;
3478 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003479 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00003480
Daniel Veillardfd573f12003-03-16 17:52:32 +00003481 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003482 if (def == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003483 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003484 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00003485
3486 type = xmlGetProp(node, BAD_CAST "type");
3487 if (type != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003488 xmlRelaxNGNormExtSpace(type);
3489 if (xmlValidateNCName(type, 0)) {
3490 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3491 "value type '%s' is not an NCName\n", type, NULL);
3492 }
3493 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3494 if (library == NULL)
3495 library =
3496 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillardedc91922003-01-26 00:52:04 +00003497
Daniel Veillard4c004142003-10-07 11:33:24 +00003498 def->name = type;
3499 def->ns = library;
Daniel Veillardedc91922003-01-26 00:52:04 +00003500
Daniel Veillard4c004142003-10-07 11:33:24 +00003501 lib = (xmlRelaxNGTypeLibraryPtr)
3502 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3503 if (lib == NULL) {
3504 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3505 "Use of unregistered type library '%s'\n", library,
3506 NULL);
3507 def->data = NULL;
3508 } else {
3509 def->data = lib;
3510 if (lib->have == NULL) {
3511 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3512 "Internal error with type library '%s': no 'have'\n",
3513 library, NULL);
3514 } else {
3515 success = lib->have(lib->data, def->name);
3516 if (success != 1) {
3517 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3518 "Error type '%s' is not exported by type library '%s'\n",
3519 def->name, library);
3520 }
3521 }
3522 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003523 }
3524 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003525 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00003526 } else if (((node->children->type != XML_TEXT_NODE) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00003527 (node->children->type != XML_CDATA_SECTION_NODE)) ||
3528 (node->children->next != NULL)) {
3529 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3530 "Expecting a single text value for <value>content\n",
3531 NULL, NULL);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003532 } else if (def != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003533 def->value = xmlNodeGetContent(node);
3534 if (def->value == NULL) {
3535 xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3536 "Element <value> has no content\n", NULL, NULL);
3537 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3538 void *val = NULL;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003539
Daniel Veillard4c004142003-10-07 11:33:24 +00003540 success =
3541 lib->check(lib->data, def->name, def->value, &val, node);
3542 if (success != 1) {
3543 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3544 "Value '%s' is not acceptable for type '%s'\n",
3545 def->value, def->name);
3546 } else {
3547 if (val != NULL)
3548 def->attrs = val;
3549 }
3550 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003551 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003552 return (def);
Daniel Veillardedc91922003-01-26 00:52:04 +00003553}
3554
3555/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003556 * xmlRelaxNGParseData:
3557 * @ctxt: a Relax-NG parser context
3558 * @node: the data node.
3559 *
3560 * parse the content of a RelaxNG data node.
3561 *
3562 * Returns the definition pointer or NULL in case of error
3563 */
3564static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00003565xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3566{
Daniel Veillard416589a2003-02-17 17:25:42 +00003567 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003568 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003569 xmlRelaxNGTypeLibraryPtr lib;
3570 xmlChar *type;
3571 xmlChar *library;
3572 xmlNodePtr content;
3573 int tmp;
3574
3575 type = xmlGetProp(node, BAD_CAST "type");
3576 if (type == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003577 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3578 NULL);
3579 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003580 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003581 xmlRelaxNGNormExtSpace(type);
3582 if (xmlValidateNCName(type, 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003583 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3584 "data type '%s' is not an NCName\n", type, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00003585 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003586 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3587 if (library == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00003588 library =
3589 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003590
Daniel Veillardfd573f12003-03-16 17:52:32 +00003591 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003592 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003593 xmlFree(type);
3594 return (NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003595 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003596 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003597 def->name = type;
3598 def->ns = library;
3599
3600 lib = (xmlRelaxNGTypeLibraryPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00003601 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003602 if (lib == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003603 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3604 "Use of unregistered type library '%s'\n", library,
3605 NULL);
3606 def->data = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003607 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003608 def->data = lib;
3609 if (lib->have == NULL) {
3610 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3611 "Internal error with type library '%s': no 'have'\n",
3612 library, NULL);
3613 } else {
3614 tmp = lib->have(lib->data, def->name);
3615 if (tmp != 1) {
3616 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3617 "Error type '%s' is not exported by type library '%s'\n",
3618 def->name, library);
3619 } else
3620 if ((xmlStrEqual
3621 (library,
3622 BAD_CAST
3623 "http://www.w3.org/2001/XMLSchema-datatypes"))
3624 && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3625 || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3626 ctxt->idref = 1;
3627 }
3628 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003629 }
3630 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003631
3632 /*
3633 * Handle optional params
3634 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003635 while (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003636 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3637 break;
3638 if (xmlStrEqual(library,
3639 BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3640 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3641 "Type library '%s' does not allow type parameters\n",
3642 library, NULL);
3643 content = content->next;
3644 while ((content != NULL) &&
3645 (xmlStrEqual(content->name, BAD_CAST "param")))
3646 content = content->next;
3647 } else {
3648 param = xmlRelaxNGNewDefine(ctxt, node);
3649 if (param != NULL) {
3650 param->type = XML_RELAXNG_PARAM;
3651 param->name = xmlGetProp(content, BAD_CAST "name");
3652 if (param->name == NULL) {
3653 xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3654 "param has no name\n", NULL, NULL);
3655 }
3656 param->value = xmlNodeGetContent(content);
3657 if (lastparam == NULL) {
3658 def->attrs = lastparam = param;
3659 } else {
3660 lastparam->next = param;
3661 lastparam = param;
3662 }
3663 if (lib != NULL) {
3664 }
3665 }
3666 content = content->next;
3667 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003668 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003669 /*
3670 * Handle optional except
3671 */
Daniel Veillard4c004142003-10-07 11:33:24 +00003672 if ((content != NULL)
3673 && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3674 xmlNodePtr child;
3675 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
Daniel Veillard416589a2003-02-17 17:25:42 +00003676
Daniel Veillard4c004142003-10-07 11:33:24 +00003677 except = xmlRelaxNGNewDefine(ctxt, node);
3678 if (except == NULL) {
3679 return (def);
3680 }
3681 except->type = XML_RELAXNG_EXCEPT;
3682 child = content->children;
3683 if (last == NULL) {
3684 def->content = except;
3685 } else {
3686 last->next = except;
3687 }
3688 if (child == NULL) {
3689 xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3690 "except has no content\n", NULL, NULL);
3691 }
3692 while (child != NULL) {
3693 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3694 if (tmp2 != NULL) {
3695 if (last2 == NULL) {
3696 except->content = last2 = tmp2;
3697 } else {
3698 last2->next = tmp2;
3699 last2 = tmp2;
3700 }
3701 }
3702 child = child->next;
3703 }
3704 content = content->next;
Daniel Veillard416589a2003-02-17 17:25:42 +00003705 }
3706 /*
3707 * Check there is no unhandled data
3708 */
3709 if (content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003710 xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3711 "Element data has unexpected content %s\n",
3712 content->name, NULL);
Daniel Veillard416589a2003-02-17 17:25:42 +00003713 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003714
Daniel Veillard4c004142003-10-07 11:33:24 +00003715 return (def);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003716}
3717
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003718static const xmlChar *invalidName = BAD_CAST "\1";
3719
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003720/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003721 * xmlRelaxNGCompareNameClasses:
3722 * @defs1: the first element/attribute defs
3723 * @defs2: the second element/attribute defs
3724 * @name: the restriction on the name
3725 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003726 *
3727 * Compare the 2 lists of element definitions. The comparison is
3728 * that if both lists do not accept the same QNames, it returns 1
3729 * If the 2 lists can accept the same QName the comparison returns 0
3730 *
3731 * Returns 1 disttinct, 0 if equal
3732 */
3733static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003734xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
Daniel Veillard4c004142003-10-07 11:33:24 +00003735 xmlRelaxNGDefinePtr def2)
3736{
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003737 int ret = 1;
3738 xmlNode node;
3739 xmlNs ns;
3740 xmlRelaxNGValidCtxt ctxt;
Daniel Veillard4c004142003-10-07 11:33:24 +00003741
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003742 ctxt.flags = FLAGS_IGNORABLE;
3743
Daniel Veillard42f12e92003-03-07 18:32:59 +00003744 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3745
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003746 if ((def1->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003747 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3748 if (def2->type == XML_RELAXNG_TEXT)
3749 return (1);
3750 if (def1->name != NULL) {
3751 node.name = def1->name;
3752 } else {
3753 node.name = invalidName;
3754 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003755 if (def1->ns != NULL) {
3756 if (def1->ns[0] == 0) {
3757 node.ns = NULL;
3758 } else {
William M. Bracka74a6ff2004-04-02 14:03:22 +00003759 node.ns = &ns;
Daniel Veillard4c004142003-10-07 11:33:24 +00003760 ns.href = def1->ns;
3761 }
3762 } else {
William M. Bracka74a6ff2004-04-02 14:03:22 +00003763 node.ns = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00003764 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003765 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003766 if (def1->nameClass != NULL) {
3767 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3768 } else {
3769 ret = 0;
3770 }
3771 } else {
3772 ret = 1;
3773 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003774 } else if (def1->type == XML_RELAXNG_TEXT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003775 if (def2->type == XML_RELAXNG_TEXT)
3776 return (0);
3777 return (1);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003778 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003779 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003780 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003781 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003782 }
3783 if (ret == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003784 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003785 if ((def2->type == XML_RELAXNG_ELEMENT) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00003786 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3787 if (def2->name != NULL) {
3788 node.name = def2->name;
3789 } else {
3790 node.name = invalidName;
3791 }
3792 node.ns = &ns;
3793 if (def2->ns != NULL) {
3794 if (def2->ns[0] == 0) {
3795 node.ns = NULL;
3796 } else {
3797 ns.href = def2->ns;
3798 }
3799 } else {
3800 ns.href = invalidName;
3801 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003802 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003803 if (def2->nameClass != NULL) {
3804 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3805 } else {
3806 ret = 0;
3807 }
3808 } else {
3809 ret = 1;
3810 }
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003811 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00003812 TODO ret = 0;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003813 }
3814
Daniel Veillard4c004142003-10-07 11:33:24 +00003815 return (ret);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003816}
3817
3818/**
3819 * xmlRelaxNGCompareElemDefLists:
3820 * @ctxt: a Relax-NG parser context
3821 * @defs1: the first list of element/attribute defs
3822 * @defs2: the second list of element/attribute defs
3823 *
3824 * Compare the 2 lists of element or attribute definitions. The comparison
3825 * is that if both lists do not accept the same QNames, it returns 1
3826 * If the 2 lists can accept the same QName the comparison returns 0
3827 *
3828 * Returns 1 disttinct, 0 if equal
3829 */
3830static int
Daniel Veillard4c004142003-10-07 11:33:24 +00003831xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3832 ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3833 xmlRelaxNGDefinePtr * def2)
3834{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003835 xmlRelaxNGDefinePtr *basedef2 = def2;
Daniel Veillard4c004142003-10-07 11:33:24 +00003836
Daniel Veillard154877e2003-01-30 12:17:05 +00003837 if ((def1 == NULL) || (def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003838 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003839 if ((*def1 == NULL) || (*def2 == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00003840 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003841 while (*def1 != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003842 while ((*def2) != NULL) {
3843 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3844 return (0);
3845 def2++;
3846 }
3847 def2 = basedef2;
3848 def1++;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003849 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003850 return (1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003851}
3852
3853/**
Daniel Veillardce192eb2003-04-16 15:58:05 +00003854 * xmlRelaxNGGenerateAttributes:
3855 * @ctxt: a Relax-NG parser context
3856 * @def: the definition definition
3857 *
3858 * Check if the definition can only generate attributes
3859 *
3860 * Returns 1 if yes, 0 if no and -1 in case of error.
3861 */
3862static int
3863xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003864 xmlRelaxNGDefinePtr def)
3865{
Daniel Veillardce192eb2003-04-16 15:58:05 +00003866 xmlRelaxNGDefinePtr parent, cur, tmp;
3867
3868 /*
3869 * Don't run that check in case of error. Infinite recursion
3870 * becomes possible.
3871 */
3872 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003873 return (-1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003874
3875 parent = NULL;
3876 cur = def;
3877 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003878 if ((cur->type == XML_RELAXNG_ELEMENT) ||
3879 (cur->type == XML_RELAXNG_TEXT) ||
3880 (cur->type == XML_RELAXNG_DATATYPE) ||
3881 (cur->type == XML_RELAXNG_PARAM) ||
3882 (cur->type == XML_RELAXNG_LIST) ||
3883 (cur->type == XML_RELAXNG_VALUE) ||
3884 (cur->type == XML_RELAXNG_EMPTY))
3885 return (0);
3886 if ((cur->type == XML_RELAXNG_CHOICE) ||
3887 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3888 (cur->type == XML_RELAXNG_GROUP) ||
3889 (cur->type == XML_RELAXNG_ONEORMORE) ||
3890 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3891 (cur->type == XML_RELAXNG_OPTIONAL) ||
3892 (cur->type == XML_RELAXNG_PARENTREF) ||
3893 (cur->type == XML_RELAXNG_EXTERNALREF) ||
3894 (cur->type == XML_RELAXNG_REF) ||
3895 (cur->type == XML_RELAXNG_DEF)) {
3896 if (cur->content != NULL) {
3897 parent = cur;
3898 cur = cur->content;
3899 tmp = cur;
3900 while (tmp != NULL) {
3901 tmp->parent = parent;
3902 tmp = tmp->next;
3903 }
3904 continue;
3905 }
3906 }
3907 if (cur == def)
3908 break;
3909 if (cur->next != NULL) {
3910 cur = cur->next;
3911 continue;
3912 }
3913 do {
3914 cur = cur->parent;
3915 if (cur == NULL)
3916 break;
3917 if (cur == def)
3918 return (1);
3919 if (cur->next != NULL) {
3920 cur = cur->next;
3921 break;
3922 }
3923 } while (cur != NULL);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003924 }
Daniel Veillard4c004142003-10-07 11:33:24 +00003925 return (1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00003926}
Daniel Veillard4c004142003-10-07 11:33:24 +00003927
Daniel Veillardce192eb2003-04-16 15:58:05 +00003928/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003929 * xmlRelaxNGGetElements:
3930 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003931 * @def: the definition definition
3932 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003933 *
3934 * Compute the list of top elements a definition can generate
3935 *
3936 * Returns a list of elements or NULL if none was found.
3937 */
3938static xmlRelaxNGDefinePtr *
3939xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00003940 xmlRelaxNGDefinePtr def, int eora)
3941{
Daniel Veillardfd573f12003-03-16 17:52:32 +00003942 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003943 int len = 0;
3944 int max = 0;
3945
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003946 /*
3947 * Don't run that check in case of error. Infinite recursion
3948 * becomes possible.
3949 */
3950 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00003951 return (NULL);
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003952
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003953 parent = NULL;
3954 cur = def;
3955 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003956 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3957 (cur->type == XML_RELAXNG_TEXT))) ||
3958 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
3959 if (ret == NULL) {
3960 max = 10;
3961 ret = (xmlRelaxNGDefinePtr *)
3962 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3963 if (ret == NULL) {
3964 xmlRngPErrMemory(ctxt, "getting element list\n");
3965 return (NULL);
3966 }
3967 } else if (max <= len) {
Daniel Veillard079f6a72004-09-23 13:15:03 +00003968 xmlRelaxNGDefinePtr *temp;
3969
Daniel Veillard4c004142003-10-07 11:33:24 +00003970 max *= 2;
Daniel Veillard079f6a72004-09-23 13:15:03 +00003971 temp = xmlRealloc(ret,
Daniel Veillard4c004142003-10-07 11:33:24 +00003972 (max + 1) * sizeof(xmlRelaxNGDefinePtr));
Daniel Veillard079f6a72004-09-23 13:15:03 +00003973 if (temp == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003974 xmlRngPErrMemory(ctxt, "getting element list\n");
Daniel Veillard079f6a72004-09-23 13:15:03 +00003975 xmlFree(ret);
Daniel Veillard4c004142003-10-07 11:33:24 +00003976 return (NULL);
3977 }
Daniel Veillard079f6a72004-09-23 13:15:03 +00003978 ret = temp;
Daniel Veillard4c004142003-10-07 11:33:24 +00003979 }
3980 ret[len++] = cur;
3981 ret[len] = NULL;
3982 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3983 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3984 (cur->type == XML_RELAXNG_GROUP) ||
3985 (cur->type == XML_RELAXNG_ONEORMORE) ||
3986 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3987 (cur->type == XML_RELAXNG_OPTIONAL) ||
3988 (cur->type == XML_RELAXNG_PARENTREF) ||
3989 (cur->type == XML_RELAXNG_REF) ||
William M. Brack236c8c02004-03-20 11:32:36 +00003990 (cur->type == XML_RELAXNG_DEF) ||
3991 (cur->type == XML_RELAXNG_EXTERNALREF)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00003992 /*
3993 * Don't go within elements or attributes or string values.
3994 * Just gather the element top list
3995 */
3996 if (cur->content != NULL) {
3997 parent = cur;
3998 cur = cur->content;
3999 tmp = cur;
4000 while (tmp != NULL) {
4001 tmp->parent = parent;
4002 tmp = tmp->next;
4003 }
4004 continue;
4005 }
4006 }
4007 if (cur == def)
4008 break;
4009 if (cur->next != NULL) {
4010 cur = cur->next;
4011 continue;
4012 }
4013 do {
4014 cur = cur->parent;
4015 if (cur == NULL)
4016 break;
4017 if (cur == def)
4018 return (ret);
4019 if (cur->next != NULL) {
4020 cur = cur->next;
4021 break;
4022 }
4023 } while (cur != NULL);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004024 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004025 return (ret);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004026}
Daniel Veillard4c004142003-10-07 11:33:24 +00004027
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004028/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004029 * xmlRelaxNGCheckChoiceDeterminism:
4030 * @ctxt: a Relax-NG parser context
4031 * @def: the choice definition
4032 *
4033 * Also used to find indeterministic pattern in choice
4034 */
4035static void
4036xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004037 xmlRelaxNGDefinePtr def)
4038{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004039 xmlRelaxNGDefinePtr **list;
4040 xmlRelaxNGDefinePtr cur;
4041 int nbchild = 0, i, j, ret;
4042 int is_nullable = 0;
4043 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004044 xmlHashTablePtr triage = NULL;
4045 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004046
Daniel Veillard4c004142003-10-07 11:33:24 +00004047 if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
4048 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004049
Daniel Veillarde063f482003-03-21 16:53:17 +00004050 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004051 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004052
Daniel Veillardfd573f12003-03-16 17:52:32 +00004053 /*
4054 * Don't run that check in case of error. Infinite recursion
4055 * becomes possible.
4056 */
4057 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004058 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004059
4060 is_nullable = xmlRelaxNGIsNullable(def);
4061
4062 cur = def->content;
4063 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004064 nbchild++;
4065 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004066 }
4067
4068 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004069 sizeof(xmlRelaxNGDefinePtr
4070 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004071 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004072 xmlRngPErrMemory(ctxt, "building choice\n");
4073 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004074 }
4075 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004076 /*
4077 * a bit strong but safe
4078 */
4079 if (is_nullable == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004080 triage = xmlHashCreate(10);
Daniel Veillarde063f482003-03-21 16:53:17 +00004081 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004082 is_triable = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00004083 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004084 cur = def->content;
4085 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004086 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4087 if ((list[i] == NULL) || (list[i][0] == NULL)) {
4088 is_triable = 0;
4089 } else if (is_triable == 1) {
4090 xmlRelaxNGDefinePtr *tmp;
4091 int res;
Daniel Veillarde063f482003-03-21 16:53:17 +00004092
Daniel Veillard4c004142003-10-07 11:33:24 +00004093 tmp = list[i];
4094 while ((*tmp != NULL) && (is_triable == 1)) {
4095 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4096 res = xmlHashAddEntry2(triage,
4097 BAD_CAST "#text", NULL,
4098 (void *) cur);
4099 if (res != 0)
4100 is_triable = -1;
4101 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4102 ((*tmp)->name != NULL)) {
4103 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4104 res = xmlHashAddEntry2(triage,
4105 (*tmp)->name, NULL,
4106 (void *) cur);
4107 else
4108 res = xmlHashAddEntry2(triage,
4109 (*tmp)->name, (*tmp)->ns,
4110 (void *) cur);
4111 if (res != 0)
4112 is_triable = -1;
4113 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4114 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4115 res = xmlHashAddEntry2(triage,
4116 BAD_CAST "#any", NULL,
4117 (void *) cur);
4118 else
4119 res = xmlHashAddEntry2(triage,
4120 BAD_CAST "#any", (*tmp)->ns,
4121 (void *) cur);
4122 if (res != 0)
4123 is_triable = -1;
4124 } else {
4125 is_triable = -1;
4126 }
4127 tmp++;
4128 }
4129 }
4130 i++;
4131 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004132 }
4133
Daniel Veillard4c004142003-10-07 11:33:24 +00004134 for (i = 0; i < nbchild; i++) {
4135 if (list[i] == NULL)
4136 continue;
4137 for (j = 0; j < i; j++) {
4138 if (list[j] == NULL)
4139 continue;
4140 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4141 if (ret == 0) {
4142 is_indeterminist = 1;
4143 }
4144 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004145 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004146 for (i = 0; i < nbchild; i++) {
4147 if (list[i] != NULL)
4148 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004149 }
4150
4151 xmlFree(list);
4152 if (is_indeterminist) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004153 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004154 }
Daniel Veillarde063f482003-03-21 16:53:17 +00004155 if (is_triable == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004156 def->dflags |= IS_TRIABLE;
4157 def->data = triage;
Daniel Veillarde063f482003-03-21 16:53:17 +00004158 } else if (triage != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004159 xmlHashFree(triage, NULL);
Daniel Veillarde063f482003-03-21 16:53:17 +00004160 }
4161 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004162}
4163
4164/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004165 * xmlRelaxNGCheckGroupAttrs:
4166 * @ctxt: a Relax-NG parser context
4167 * @def: the group definition
4168 *
4169 * Detects violations of rule 7.3
4170 */
4171static void
4172xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00004173 xmlRelaxNGDefinePtr def)
4174{
Daniel Veillardfd573f12003-03-16 17:52:32 +00004175 xmlRelaxNGDefinePtr **list;
4176 xmlRelaxNGDefinePtr cur;
4177 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004178
4179 if ((def == NULL) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00004180 ((def->type != XML_RELAXNG_GROUP) &&
4181 (def->type != XML_RELAXNG_ELEMENT)))
4182 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004183
Daniel Veillarde063f482003-03-21 16:53:17 +00004184 if (def->dflags & IS_PROCESSED)
Daniel Veillard4c004142003-10-07 11:33:24 +00004185 return;
Daniel Veillarde063f482003-03-21 16:53:17 +00004186
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004187 /*
4188 * Don't run that check in case of error. Infinite recursion
4189 * becomes possible.
4190 */
4191 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004192 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004193
Daniel Veillardfd573f12003-03-16 17:52:32 +00004194 cur = def->attrs;
4195 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004196 nbchild++;
4197 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004198 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004199 cur = def->content;
4200 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004201 nbchild++;
4202 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004203 }
4204
4205 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
Daniel Veillard4c004142003-10-07 11:33:24 +00004206 sizeof(xmlRelaxNGDefinePtr
4207 *));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004208 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004209 xmlRngPErrMemory(ctxt, "building group\n");
4210 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004211 }
4212 i = 0;
4213 cur = def->attrs;
4214 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004215 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4216 i++;
4217 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004218 }
4219 cur = def->content;
4220 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004221 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4222 i++;
4223 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004224 }
4225
Daniel Veillard4c004142003-10-07 11:33:24 +00004226 for (i = 0; i < nbchild; i++) {
4227 if (list[i] == NULL)
4228 continue;
4229 for (j = 0; j < i; j++) {
4230 if (list[j] == NULL)
4231 continue;
4232 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4233 if (ret == 0) {
4234 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4235 "Attributes conflicts in group\n", NULL, NULL);
4236 }
4237 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004238 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004239 for (i = 0; i < nbchild; i++) {
4240 if (list[i] != NULL)
4241 xmlFree(list[i]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004242 }
4243
4244 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00004245 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004246}
4247
4248/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004249 * xmlRelaxNGComputeInterleaves:
4250 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004251 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00004252 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004253 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00004254 * A lot of work for preprocessing interleave definitions
4255 * is potentially needed to get a decent execution speed at runtime
4256 * - trying to get a total order on the element nodes generated
4257 * by the interleaves, order the list of interleave definitions
4258 * following that order.
4259 * - if <text/> is used to handle mixed content, it is better to
4260 * flag this in the define and simplify the runtime checking
4261 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004262 */
4263static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00004264xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
Daniel Veillard4c004142003-10-07 11:33:24 +00004265 xmlRelaxNGParserCtxtPtr ctxt,
4266 xmlChar * name ATTRIBUTE_UNUSED)
4267{
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004268 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004269
Daniel Veillardfd573f12003-03-16 17:52:32 +00004270 xmlRelaxNGPartitionPtr partitions = NULL;
4271 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4272 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillard4c004142003-10-07 11:33:24 +00004273 int i, j, ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004274 int nbgroups = 0;
4275 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004276 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004277 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004278
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004279 /*
4280 * Don't run that check in case of error. Infinite recursion
4281 * becomes possible.
4282 */
4283 if (ctxt->nbErrors != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004284 return;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004285
Daniel Veillardfd573f12003-03-16 17:52:32 +00004286#ifdef DEBUG_INTERLEAVE
4287 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00004288 "xmlRelaxNGComputeInterleaves(%s)\n", name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004289#endif
4290 cur = def->content;
4291 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004292 nbchild++;
4293 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004294 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004295
Daniel Veillardfd573f12003-03-16 17:52:32 +00004296#ifdef DEBUG_INTERLEAVE
4297 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
4298#endif
4299 groups = (xmlRelaxNGInterleaveGroupPtr *)
Daniel Veillard4c004142003-10-07 11:33:24 +00004300 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004301 if (groups == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004302 goto error;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004303 cur = def->content;
4304 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004305 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4306 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4307 if (groups[nbgroups] == NULL)
4308 goto error;
4309 if (cur->type == XML_RELAXNG_TEXT)
4310 is_mixed++;
4311 groups[nbgroups]->rule = cur;
4312 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4313 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4314 nbgroups++;
4315 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004316 }
4317#ifdef DEBUG_INTERLEAVE
4318 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4319#endif
4320
4321 /*
4322 * Let's check that all rules makes a partitions according to 7.4
4323 */
4324 partitions = (xmlRelaxNGPartitionPtr)
Daniel Veillard4c004142003-10-07 11:33:24 +00004325 xmlMalloc(sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004326 if (partitions == NULL)
4327 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004328 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004329 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004330 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillard4c004142003-10-07 11:33:24 +00004331 for (i = 0; i < nbgroups; i++) {
4332 group = groups[i];
4333 for (j = i + 1; j < nbgroups; j++) {
4334 if (groups[j] == NULL)
4335 continue;
4336
4337 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4338 groups[j]->defs);
4339 if (ret == 0) {
4340 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4341 "Element or text conflicts in interleave\n",
4342 NULL, NULL);
4343 }
4344 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4345 groups[j]->attrs);
4346 if (ret == 0) {
4347 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4348 "Attributes conflicts in interleave\n", NULL,
4349 NULL);
4350 }
4351 }
4352 tmp = group->defs;
4353 if ((tmp != NULL) && (*tmp != NULL)) {
4354 while (*tmp != NULL) {
4355 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4356 res = xmlHashAddEntry2(partitions->triage,
4357 BAD_CAST "#text", NULL,
4358 (void *) (long) (i + 1));
4359 if (res != 0)
4360 is_determinist = -1;
4361 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4362 ((*tmp)->name != NULL)) {
4363 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4364 res = xmlHashAddEntry2(partitions->triage,
4365 (*tmp)->name, NULL,
4366 (void *) (long) (i + 1));
4367 else
4368 res = xmlHashAddEntry2(partitions->triage,
4369 (*tmp)->name, (*tmp)->ns,
4370 (void *) (long) (i + 1));
4371 if (res != 0)
4372 is_determinist = -1;
4373 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4374 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4375 res = xmlHashAddEntry2(partitions->triage,
4376 BAD_CAST "#any", NULL,
4377 (void *) (long) (i + 1));
4378 else
4379 res = xmlHashAddEntry2(partitions->triage,
4380 BAD_CAST "#any", (*tmp)->ns,
4381 (void *) (long) (i + 1));
4382 if ((*tmp)->nameClass != NULL)
4383 is_determinist = 2;
4384 if (res != 0)
4385 is_determinist = -1;
4386 } else {
4387 is_determinist = -1;
4388 }
4389 tmp++;
4390 }
4391 } else {
4392 is_determinist = 0;
4393 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004394 }
4395 partitions->groups = groups;
4396
4397 /*
4398 * and save the partition list back in the def
4399 */
4400 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004401 if (is_mixed != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00004402 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004403 if (is_determinist == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00004404 partitions->flags = IS_DETERMINIST;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004405 if (is_determinist == 2)
Daniel Veillard4c004142003-10-07 11:33:24 +00004406 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004407 return;
4408
Daniel Veillard4c004142003-10-07 11:33:24 +00004409 error:
4410 xmlRngPErrMemory(ctxt, "in interleave computation\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004411 if (groups != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004412 for (i = 0; i < nbgroups; i++)
4413 if (groups[i] != NULL) {
4414 if (groups[i]->defs != NULL)
4415 xmlFree(groups[i]->defs);
4416 xmlFree(groups[i]);
4417 }
4418 xmlFree(groups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004419 }
4420 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004421}
4422
4423/**
4424 * xmlRelaxNGParseInterleave:
4425 * @ctxt: a Relax-NG parser context
4426 * @node: the data node.
4427 *
4428 * parse the content of a RelaxNG interleave node.
4429 *
4430 * Returns the definition pointer or NULL in case of error
4431 */
4432static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004433xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4434{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004435 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004436 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004437 xmlNodePtr child;
4438
Daniel Veillardfd573f12003-03-16 17:52:32 +00004439 def = xmlRelaxNGNewDefine(ctxt, node);
4440 if (def == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004441 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004442 }
4443 def->type = XML_RELAXNG_INTERLEAVE;
4444
4445 if (ctxt->interleaves == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00004446 ctxt->interleaves = xmlHashCreate(10);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004447 if (ctxt->interleaves == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004448 xmlRngPErrMemory(ctxt, "create interleaves\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00004449 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004450 char name[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00004451
Daniel Veillard4c004142003-10-07 11:33:24 +00004452 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4453 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4454 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4455 "Failed to add %s to hash table\n",
4456 (const xmlChar *) name, NULL);
4457 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004458 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004459 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004460 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004461 xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4462 "Element interleave is empty\n", NULL, NULL);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004463 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004464 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004465 if (IS_RELAXNG(child, "element")) {
4466 cur = xmlRelaxNGParseElement(ctxt, child);
4467 } else {
4468 cur = xmlRelaxNGParsePattern(ctxt, child);
4469 }
4470 if (cur != NULL) {
4471 cur->parent = def;
4472 if (last == NULL) {
4473 def->content = last = cur;
4474 } else {
4475 last->next = cur;
4476 last = cur;
4477 }
4478 }
4479 child = child->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004480 }
4481
Daniel Veillard4c004142003-10-07 11:33:24 +00004482 return (def);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004483}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004484
4485/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004486 * xmlRelaxNGParseInclude:
4487 * @ctxt: a Relax-NG parser context
4488 * @node: the include node
4489 *
4490 * Integrate the content of an include node in the current grammar
4491 *
4492 * Returns 0 in case of success or -1 in case of error
4493 */
4494static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004495xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4496{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004497 xmlRelaxNGIncludePtr incl;
4498 xmlNodePtr root;
4499 int ret = 0, tmp;
4500
Daniel Veillard807daf82004-02-22 22:13:27 +00004501 incl = node->psvi;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004502 if (incl == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004503 xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4504 "Include node has no data\n", NULL, NULL);
4505 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004506 }
4507 root = xmlDocGetRootElement(incl->doc);
4508 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004509 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4510 NULL, NULL);
4511 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004512 }
4513 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004514 xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4515 "Include document root is not a grammar\n", NULL, NULL);
4516 return (-1);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004517 }
4518
4519 /*
4520 * Merge the definition from both the include and the internal list
4521 */
4522 if (root->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004523 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4524 if (tmp != 0)
4525 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004526 }
4527 if (node->children != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004528 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4529 if (tmp != 0)
4530 ret = -1;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004531 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004532 return (ret);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004533}
4534
4535/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004536 * xmlRelaxNGParseDefine:
4537 * @ctxt: a Relax-NG parser context
4538 * @node: the define node
4539 *
4540 * parse the content of a RelaxNG define element node.
4541 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004542 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004543 */
4544static int
Daniel Veillard4c004142003-10-07 11:33:24 +00004545xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4546{
Daniel Veillard276be4a2003-01-24 01:03:34 +00004547 xmlChar *name;
4548 int ret = 0, tmp;
4549 xmlRelaxNGDefinePtr def;
4550 const xmlChar *olddefine;
4551
4552 name = xmlGetProp(node, BAD_CAST "name");
4553 if (name == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004554 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4555 "define has no name\n", NULL, NULL);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004556 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004557 xmlRelaxNGNormExtSpace(name);
4558 if (xmlValidateNCName(name, 0)) {
4559 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4560 "define name '%s' is not an NCName\n", name, NULL);
4561 }
4562 def = xmlRelaxNGNewDefine(ctxt, node);
4563 if (def == NULL) {
4564 xmlFree(name);
4565 return (-1);
4566 }
4567 def->type = XML_RELAXNG_DEF;
4568 def->name = name;
4569 if (node->children == NULL) {
4570 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4571 "define has no children\n", NULL, NULL);
4572 } else {
4573 olddefine = ctxt->define;
4574 ctxt->define = name;
4575 def->content =
4576 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4577 ctxt->define = olddefine;
4578 }
4579 if (ctxt->grammar->defs == NULL)
4580 ctxt->grammar->defs = xmlHashCreate(10);
4581 if (ctxt->grammar->defs == NULL) {
4582 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4583 "Could not create definition hash\n", NULL, NULL);
4584 ret = -1;
4585 } else {
4586 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4587 if (tmp < 0) {
4588 xmlRelaxNGDefinePtr prev;
Daniel Veillard154877e2003-01-30 12:17:05 +00004589
Daniel Veillard4c004142003-10-07 11:33:24 +00004590 prev = xmlHashLookup(ctxt->grammar->defs, name);
4591 if (prev == NULL) {
4592 xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4593 "Internal error on define aggregation of %s\n",
4594 name, NULL);
4595 ret = -1;
4596 } else {
4597 while (prev->nextHash != NULL)
4598 prev = prev->nextHash;
4599 prev->nextHash = def;
4600 }
4601 }
4602 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004603 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004604 return (ret);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004605}
4606
4607/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004608 * xmlRelaxNGProcessExternalRef:
4609 * @ctxt: the parser context
4610 * @node: the externlRef node
4611 *
4612 * Process and compile an externlRef node
4613 *
4614 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4615 */
4616static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004617xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4618{
Daniel Veillardfebcca42003-02-16 15:44:18 +00004619 xmlRelaxNGDocumentPtr docu;
4620 xmlNodePtr root, tmp;
4621 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004622 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004623 xmlRelaxNGDefinePtr def;
4624
Daniel Veillard807daf82004-02-22 22:13:27 +00004625 docu = node->psvi;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004626 if (docu != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004627 def = xmlRelaxNGNewDefine(ctxt, node);
4628 if (def == NULL)
4629 return (NULL);
4630 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004631
Daniel Veillard4c004142003-10-07 11:33:24 +00004632 if (docu->content == NULL) {
4633 /*
4634 * Then do the parsing for good
4635 */
4636 root = xmlDocGetRootElement(docu->doc);
4637 if (root == NULL) {
4638 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
4639 "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
4640 NULL);
4641 return (NULL);
4642 }
4643 /*
4644 * ns transmission rules
4645 */
4646 ns = xmlGetProp(root, BAD_CAST "ns");
4647 if (ns == NULL) {
4648 tmp = node;
4649 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
4650 ns = xmlGetProp(tmp, BAD_CAST "ns");
4651 if (ns != NULL) {
4652 break;
4653 }
4654 tmp = tmp->parent;
4655 }
4656 if (ns != NULL) {
4657 xmlSetProp(root, BAD_CAST "ns", ns);
4658 newNs = 1;
4659 xmlFree(ns);
4660 }
4661 } else {
4662 xmlFree(ns);
4663 }
Daniel Veillardfebcca42003-02-16 15:44:18 +00004664
Daniel Veillard4c004142003-10-07 11:33:24 +00004665 /*
4666 * Parsing to get a precompiled schemas.
4667 */
4668 oldflags = ctxt->flags;
4669 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4670 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4671 ctxt->flags = oldflags;
4672 if ((docu->schema != NULL) &&
4673 (docu->schema->topgrammar != NULL)) {
4674 docu->content = docu->schema->topgrammar->start;
4675 }
4676
4677 /*
4678 * the externalRef may be reused in a different ns context
4679 */
4680 if (newNs == 1) {
4681 xmlUnsetProp(root, BAD_CAST "ns");
4682 }
4683 }
4684 def->content = docu->content;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004685 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004686 def = NULL;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004687 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004688 return (def);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004689}
4690
4691/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004692 * xmlRelaxNGParsePattern:
4693 * @ctxt: a Relax-NG parser context
4694 * @node: the pattern node.
4695 *
4696 * parse the content of a RelaxNG pattern node.
4697 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004698 * Returns the definition pointer or NULL in case of error or if no
4699 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004700 */
4701static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00004702xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4703{
Daniel Veillard6eadf632003-01-23 18:29:16 +00004704 xmlRelaxNGDefinePtr def = NULL;
4705
Daniel Veillardd2298792003-02-14 16:54:11 +00004706 if (node == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004707 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004708 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004709 if (IS_RELAXNG(node, "element")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004710 def = xmlRelaxNGParseElement(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004711 } else if (IS_RELAXNG(node, "attribute")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004712 def = xmlRelaxNGParseAttribute(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004713 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004714 def = xmlRelaxNGNewDefine(ctxt, node);
4715 if (def == NULL)
4716 return (NULL);
4717 def->type = XML_RELAXNG_EMPTY;
4718 if (node->children != NULL) {
4719 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
4720 "empty: had a child node\n", NULL, NULL);
4721 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004722 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004723 def = xmlRelaxNGNewDefine(ctxt, node);
4724 if (def == NULL)
4725 return (NULL);
4726 def->type = XML_RELAXNG_TEXT;
4727 if (node->children != NULL) {
4728 xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
4729 "text: had a child node\n", NULL, NULL);
4730 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004731 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004732 def = xmlRelaxNGNewDefine(ctxt, node);
4733 if (def == NULL)
4734 return (NULL);
4735 def->type = XML_RELAXNG_ZEROORMORE;
4736 if (node->children == NULL) {
4737 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4738 "Element %s is empty\n", node->name, NULL);
4739 } else {
4740 def->content =
4741 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4742 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004743 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004744 def = xmlRelaxNGNewDefine(ctxt, node);
4745 if (def == NULL)
4746 return (NULL);
4747 def->type = XML_RELAXNG_ONEORMORE;
4748 if (node->children == NULL) {
4749 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4750 "Element %s is empty\n", node->name, NULL);
4751 } else {
4752 def->content =
4753 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4754 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004755 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004756 def = xmlRelaxNGNewDefine(ctxt, node);
4757 if (def == NULL)
4758 return (NULL);
4759 def->type = XML_RELAXNG_OPTIONAL;
4760 if (node->children == NULL) {
4761 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4762 "Element %s is empty\n", node->name, NULL);
4763 } else {
4764 def->content =
4765 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4766 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004767 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004768 def = xmlRelaxNGNewDefine(ctxt, node);
4769 if (def == NULL)
4770 return (NULL);
4771 def->type = XML_RELAXNG_CHOICE;
4772 if (node->children == NULL) {
4773 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4774 "Element %s is empty\n", node->name, NULL);
4775 } else {
4776 def->content =
4777 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4778 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004779 } else if (IS_RELAXNG(node, "group")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004780 def = xmlRelaxNGNewDefine(ctxt, node);
4781 if (def == NULL)
4782 return (NULL);
4783 def->type = XML_RELAXNG_GROUP;
4784 if (node->children == NULL) {
4785 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4786 "Element %s is empty\n", node->name, NULL);
4787 } else {
4788 def->content =
4789 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4790 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004791 } else if (IS_RELAXNG(node, "ref")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004792 def = xmlRelaxNGNewDefine(ctxt, node);
4793 if (def == NULL)
4794 return (NULL);
4795 def->type = XML_RELAXNG_REF;
4796 def->name = xmlGetProp(node, BAD_CAST "name");
4797 if (def->name == NULL) {
4798 xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
4799 NULL, NULL);
4800 } else {
4801 xmlRelaxNGNormExtSpace(def->name);
4802 if (xmlValidateNCName(def->name, 0)) {
4803 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
4804 "ref name '%s' is not an NCName\n", def->name,
4805 NULL);
4806 }
4807 }
4808 if (node->children != NULL) {
4809 xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
4810 NULL, NULL);
4811 }
4812 if (ctxt->grammar->refs == NULL)
4813 ctxt->grammar->refs = xmlHashCreate(10);
4814 if (ctxt->grammar->refs == NULL) {
4815 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4816 "Could not create references hash\n", NULL, NULL);
4817 def = NULL;
4818 } else {
4819 int tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004820
Daniel Veillard4c004142003-10-07 11:33:24 +00004821 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4822 if (tmp < 0) {
4823 xmlRelaxNGDefinePtr prev;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004824
Daniel Veillard4c004142003-10-07 11:33:24 +00004825 prev = (xmlRelaxNGDefinePtr)
4826 xmlHashLookup(ctxt->grammar->refs, def->name);
4827 if (prev == NULL) {
4828 if (def->name != NULL) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004829 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4830 "Error refs definitions '%s'\n",
4831 def->name, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004832 } else {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00004833 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4834 "Error refs definitions\n",
4835 NULL, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00004836 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004837 def = NULL;
4838 } else {
4839 def->nextHash = prev->nextHash;
4840 prev->nextHash = def;
4841 }
4842 }
4843 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004844 } else if (IS_RELAXNG(node, "data")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004845 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004846 } else if (IS_RELAXNG(node, "value")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004847 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004848 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004849 def = xmlRelaxNGNewDefine(ctxt, node);
4850 if (def == NULL)
4851 return (NULL);
4852 def->type = XML_RELAXNG_LIST;
4853 if (node->children == NULL) {
4854 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4855 "Element %s is empty\n", node->name, NULL);
4856 } else {
4857 def->content =
4858 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4859 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004860 } else if (IS_RELAXNG(node, "interleave")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004861 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004862 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004863 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004864 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004865 def = xmlRelaxNGNewDefine(ctxt, node);
4866 if (def == NULL)
4867 return (NULL);
4868 def->type = XML_RELAXNG_NOT_ALLOWED;
4869 if (node->children != NULL) {
4870 xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
4871 "xmlRelaxNGParse: notAllowed element is not empty\n",
4872 NULL, NULL);
4873 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004874 } else if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004875 xmlRelaxNGGrammarPtr grammar, old;
4876 xmlRelaxNGGrammarPtr oldparent;
Daniel Veillard419a7682003-02-03 23:22:49 +00004877
Daniel Veillardc482e262003-02-26 14:48:48 +00004878#ifdef DEBUG_GRAMMAR
Daniel Veillard4c004142003-10-07 11:33:24 +00004879 xmlGenericError(xmlGenericErrorContext,
4880 "Found <grammar> pattern\n");
Daniel Veillardc482e262003-02-26 14:48:48 +00004881#endif
4882
Daniel Veillard4c004142003-10-07 11:33:24 +00004883 oldparent = ctxt->parentgrammar;
4884 old = ctxt->grammar;
4885 ctxt->parentgrammar = old;
4886 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4887 if (old != NULL) {
4888 ctxt->grammar = old;
4889 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004890#if 0
Daniel Veillard4c004142003-10-07 11:33:24 +00004891 if (grammar != NULL) {
4892 grammar->next = old->next;
4893 old->next = grammar;
4894 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004895#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00004896 }
4897 if (grammar != NULL)
4898 def = grammar->start;
4899 else
4900 def = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00004901 } else if (IS_RELAXNG(node, "parentRef")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004902 if (ctxt->parentgrammar == NULL) {
4903 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
4904 "Use of parentRef without a parent grammar\n", NULL,
4905 NULL);
4906 return (NULL);
4907 }
4908 def = xmlRelaxNGNewDefine(ctxt, node);
4909 if (def == NULL)
4910 return (NULL);
4911 def->type = XML_RELAXNG_PARENTREF;
4912 def->name = xmlGetProp(node, BAD_CAST "name");
4913 if (def->name == NULL) {
4914 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
4915 "parentRef has no name\n", NULL, NULL);
4916 } else {
4917 xmlRelaxNGNormExtSpace(def->name);
4918 if (xmlValidateNCName(def->name, 0)) {
4919 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
4920 "parentRef name '%s' is not an NCName\n",
4921 def->name, NULL);
4922 }
4923 }
4924 if (node->children != NULL) {
4925 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
4926 "parentRef is not empty\n", NULL, NULL);
4927 }
4928 if (ctxt->parentgrammar->refs == NULL)
4929 ctxt->parentgrammar->refs = xmlHashCreate(10);
4930 if (ctxt->parentgrammar->refs == NULL) {
4931 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4932 "Could not create references hash\n", NULL, NULL);
4933 def = NULL;
4934 } else if (def->name != NULL) {
4935 int tmp;
Daniel Veillard419a7682003-02-03 23:22:49 +00004936
Daniel Veillard4c004142003-10-07 11:33:24 +00004937 tmp =
4938 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4939 if (tmp < 0) {
4940 xmlRelaxNGDefinePtr prev;
Daniel Veillard419a7682003-02-03 23:22:49 +00004941
Daniel Veillard4c004142003-10-07 11:33:24 +00004942 prev = (xmlRelaxNGDefinePtr)
4943 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4944 if (prev == NULL) {
4945 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4946 "Internal error parentRef definitions '%s'\n",
4947 def->name, NULL);
4948 def = NULL;
4949 } else {
4950 def->nextHash = prev->nextHash;
4951 prev->nextHash = def;
4952 }
4953 }
4954 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004955 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00004956 if (node->children == NULL) {
4957 xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
4958 NULL, NULL);
4959 def = NULL;
4960 } else {
4961 def = xmlRelaxNGParseInterleave(ctxt, node);
4962 if (def != NULL) {
4963 xmlRelaxNGDefinePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004964
Daniel Veillard4c004142003-10-07 11:33:24 +00004965 if ((def->content != NULL) && (def->content->next != NULL)) {
4966 tmp = xmlRelaxNGNewDefine(ctxt, node);
4967 if (tmp != NULL) {
4968 tmp->type = XML_RELAXNG_GROUP;
4969 tmp->content = def->content;
4970 def->content = tmp;
4971 }
4972 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004973
Daniel Veillard4c004142003-10-07 11:33:24 +00004974 tmp = xmlRelaxNGNewDefine(ctxt, node);
4975 if (tmp == NULL)
4976 return (def);
4977 tmp->type = XML_RELAXNG_TEXT;
4978 tmp->next = def->content;
4979 def->content = tmp;
4980 }
4981 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004982 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00004983 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
4984 "Unexpected node %s is not a pattern\n", node->name,
4985 NULL);
4986 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004987 }
Daniel Veillard4c004142003-10-07 11:33:24 +00004988 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004989}
4990
4991/**
4992 * xmlRelaxNGParseAttribute:
4993 * @ctxt: a Relax-NG parser context
4994 * @node: the element node
4995 *
4996 * parse the content of a RelaxNG attribute node.
4997 *
4998 * Returns the definition pointer or NULL in case of error.
4999 */
5000static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005001xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5002{
Daniel Veillardd2298792003-02-14 16:54:11 +00005003 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005004 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005005 int old_flags;
5006
Daniel Veillardfd573f12003-03-16 17:52:32 +00005007 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005008 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005009 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005010 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005011 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005012 child = node->children;
5013 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005014 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
5015 "xmlRelaxNGParseattribute: attribute has no children\n",
5016 NULL, NULL);
5017 return (ret);
5018 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005019 old_flags = ctxt->flags;
5020 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005021 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5022 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005023 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005024
Daniel Veillardd2298792003-02-14 16:54:11 +00005025 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005026 cur = xmlRelaxNGParsePattern(ctxt, child);
5027 if (cur != NULL) {
5028 switch (cur->type) {
5029 case XML_RELAXNG_EMPTY:
5030 case XML_RELAXNG_NOT_ALLOWED:
5031 case XML_RELAXNG_TEXT:
5032 case XML_RELAXNG_ELEMENT:
5033 case XML_RELAXNG_DATATYPE:
5034 case XML_RELAXNG_VALUE:
5035 case XML_RELAXNG_LIST:
5036 case XML_RELAXNG_REF:
5037 case XML_RELAXNG_PARENTREF:
5038 case XML_RELAXNG_EXTERNALREF:
5039 case XML_RELAXNG_DEF:
5040 case XML_RELAXNG_ONEORMORE:
5041 case XML_RELAXNG_ZEROORMORE:
5042 case XML_RELAXNG_OPTIONAL:
5043 case XML_RELAXNG_CHOICE:
5044 case XML_RELAXNG_GROUP:
5045 case XML_RELAXNG_INTERLEAVE:
5046 case XML_RELAXNG_ATTRIBUTE:
5047 ret->content = cur;
5048 cur->parent = ret;
5049 break;
5050 case XML_RELAXNG_START:
5051 case XML_RELAXNG_PARAM:
5052 case XML_RELAXNG_EXCEPT:
5053 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
5054 "attribute has invalid content\n", NULL,
5055 NULL);
5056 break;
5057 case XML_RELAXNG_NOOP:
5058 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
5059 "RNG Internal error, noop found in attribute\n",
5060 NULL, NULL);
5061 break;
5062 }
5063 }
5064 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005065 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005066 if (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005067 xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
5068 "attribute has multiple children\n", NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005069 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005070 ctxt->flags = old_flags;
Daniel Veillard4c004142003-10-07 11:33:24 +00005071 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005072}
5073
5074/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005075 * xmlRelaxNGParseExceptNameClass:
5076 * @ctxt: a Relax-NG parser context
5077 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00005078 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005079 *
5080 * parse the content of a RelaxNG nameClass node.
5081 *
5082 * Returns the definition pointer or NULL in case of error.
5083 */
5084static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00005085xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005086 xmlNodePtr node, int attr)
5087{
Daniel Veillard144fae12003-02-03 13:17:57 +00005088 xmlRelaxNGDefinePtr ret, cur, last = NULL;
5089 xmlNodePtr child;
5090
Daniel Veillardd2298792003-02-14 16:54:11 +00005091 if (!IS_RELAXNG(node, "except")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005092 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
5093 "Expecting an except node\n", NULL, NULL);
5094 return (NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005095 }
5096 if (node->next != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005097 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
5098 "exceptNameClass allows only a single except node\n",
5099 NULL, NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00005100 }
Daniel Veillard144fae12003-02-03 13:17:57 +00005101 if (node->children == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005102 xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
5103 NULL, NULL);
5104 return (NULL);
Daniel Veillard144fae12003-02-03 13:17:57 +00005105 }
5106
Daniel Veillardfd573f12003-03-16 17:52:32 +00005107 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00005108 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005109 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005110 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00005111 child = node->children;
5112 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005113 cur = xmlRelaxNGNewDefine(ctxt, child);
5114 if (cur == NULL)
5115 break;
5116 if (attr)
5117 cur->type = XML_RELAXNG_ATTRIBUTE;
5118 else
5119 cur->type = XML_RELAXNG_ELEMENT;
5120
Daniel Veillard419a7682003-02-03 23:22:49 +00005121 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005122 if (last == NULL) {
5123 ret->content = cur;
5124 } else {
5125 last->next = cur;
5126 }
5127 last = cur;
5128 }
5129 child = child->next;
Daniel Veillard144fae12003-02-03 13:17:57 +00005130 }
5131
Daniel Veillard4c004142003-10-07 11:33:24 +00005132 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005133}
5134
5135/**
5136 * xmlRelaxNGParseNameClass:
5137 * @ctxt: a Relax-NG parser context
5138 * @node: the nameClass node
5139 * @def: the current definition
5140 *
5141 * parse the content of a RelaxNG nameClass node.
5142 *
5143 * Returns the definition pointer or NULL in case of error.
5144 */
5145static xmlRelaxNGDefinePtr
5146xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
Daniel Veillard4c004142003-10-07 11:33:24 +00005147 xmlRelaxNGDefinePtr def)
5148{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005149 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005150 xmlChar *val;
5151
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005152 ret = def;
Daniel Veillard4c004142003-10-07 11:33:24 +00005153 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005154 (IS_RELAXNG(node, "nsName"))) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005155 if ((def->type != XML_RELAXNG_ELEMENT) &&
5156 (def->type != XML_RELAXNG_ATTRIBUTE)) {
5157 ret = xmlRelaxNGNewDefine(ctxt, node);
5158 if (ret == NULL)
5159 return (NULL);
5160 ret->parent = def;
5161 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5162 ret->type = XML_RELAXNG_ATTRIBUTE;
5163 else
5164 ret->type = XML_RELAXNG_ELEMENT;
5165 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005166 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005167 if (IS_RELAXNG(node, "name")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005168 val = xmlNodeGetContent(node);
5169 xmlRelaxNGNormExtSpace(val);
5170 if (xmlValidateNCName(val, 0)) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005171 if (node->parent != NULL)
5172 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5173 "Element %s name '%s' is not an NCName\n",
5174 node->parent->name, val);
5175 else
5176 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5177 "name '%s' is not an NCName\n",
5178 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005179 }
5180 ret->name = val;
5181 val = xmlGetProp(node, BAD_CAST "ns");
5182 ret->ns = val;
5183 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5184 (val != NULL) &&
5185 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005186 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
Daniel Veillard4c004142003-10-07 11:33:24 +00005187 "Attribute with namespace '%s' is not allowed\n",
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005188 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005189 }
5190 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5191 (val != NULL) &&
5192 (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
Daniel Veillard6edbfbb2003-10-07 12:17:44 +00005193 xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
5194 "Attribute with QName 'xmlns' is not allowed\n",
5195 val, NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00005196 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005197 } else if (IS_RELAXNG(node, "anyName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005198 ret->name = NULL;
5199 ret->ns = NULL;
5200 if (node->children != NULL) {
5201 ret->nameClass =
5202 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5203 (def->type ==
5204 XML_RELAXNG_ATTRIBUTE));
5205 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005206 } else if (IS_RELAXNG(node, "nsName")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005207 ret->name = NULL;
5208 ret->ns = xmlGetProp(node, BAD_CAST "ns");
5209 if (ret->ns == NULL) {
5210 xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
5211 "nsName has no ns attribute\n", NULL, NULL);
5212 }
5213 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5214 (ret->ns != NULL) &&
5215 (xmlStrEqual
5216 (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5217 xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5218 "Attribute with namespace '%s' is not allowed\n",
5219 ret->ns, NULL);
5220 }
5221 if (node->children != NULL) {
5222 ret->nameClass =
5223 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5224 (def->type ==
5225 XML_RELAXNG_ATTRIBUTE));
5226 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005227 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005228 xmlNodePtr child;
5229 xmlRelaxNGDefinePtr last = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005230
Daniel Veillard4c004142003-10-07 11:33:24 +00005231 ret = xmlRelaxNGNewDefine(ctxt, node);
5232 if (ret == NULL)
5233 return (NULL);
5234 ret->parent = def;
5235 ret->type = XML_RELAXNG_CHOICE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005236
Daniel Veillard4c004142003-10-07 11:33:24 +00005237 if (node->children == NULL) {
5238 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
5239 "Element choice is empty\n", NULL, NULL);
5240 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005241
Daniel Veillard4c004142003-10-07 11:33:24 +00005242 child = node->children;
5243 while (child != NULL) {
5244 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5245 if (tmp != NULL) {
5246 if (last == NULL) {
5247 last = ret->nameClass = tmp;
5248 } else {
5249 last->next = tmp;
5250 last = tmp;
5251 }
5252 }
5253 child = child->next;
5254 }
5255 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005256 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005257 xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
5258 "expecting name, anyName, nsName or choice : got %s\n",
5259 node->name, NULL);
5260 return (NULL);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005261 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005262 if (ret != def) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005263 if (def->nameClass == NULL) {
5264 def->nameClass = ret;
5265 } else {
5266 tmp = def->nameClass;
5267 while (tmp->next != NULL) {
5268 tmp = tmp->next;
5269 }
5270 tmp->next = ret;
5271 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005272 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005273 return (ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005274}
5275
5276/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005277 * xmlRelaxNGParseElement:
5278 * @ctxt: a Relax-NG parser context
5279 * @node: the element node
5280 *
5281 * parse the content of a RelaxNG element node.
5282 *
5283 * Returns the definition pointer or NULL in case of error.
5284 */
5285static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005286xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5287{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005288 xmlRelaxNGDefinePtr ret, cur, last;
5289 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005290 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005291
Daniel Veillardfd573f12003-03-16 17:52:32 +00005292 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005293 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005294 return (NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005295 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005296 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005297 child = node->children;
5298 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005299 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
5300 "xmlRelaxNGParseElement: element has no children\n",
5301 NULL, NULL);
5302 return (ret);
5303 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005304 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5305 if (cur != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005306 child = child->next;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005307
Daniel Veillard6eadf632003-01-23 18:29:16 +00005308 if (child == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005309 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
5310 "xmlRelaxNGParseElement: element has no content\n",
5311 NULL, NULL);
5312 return (ret);
5313 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005314 olddefine = ctxt->define;
5315 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005316 last = NULL;
5317 while (child != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005318 cur = xmlRelaxNGParsePattern(ctxt, child);
5319 if (cur != NULL) {
5320 cur->parent = ret;
5321 switch (cur->type) {
5322 case XML_RELAXNG_EMPTY:
5323 case XML_RELAXNG_NOT_ALLOWED:
5324 case XML_RELAXNG_TEXT:
5325 case XML_RELAXNG_ELEMENT:
5326 case XML_RELAXNG_DATATYPE:
5327 case XML_RELAXNG_VALUE:
5328 case XML_RELAXNG_LIST:
5329 case XML_RELAXNG_REF:
5330 case XML_RELAXNG_PARENTREF:
5331 case XML_RELAXNG_EXTERNALREF:
5332 case XML_RELAXNG_DEF:
5333 case XML_RELAXNG_ZEROORMORE:
5334 case XML_RELAXNG_ONEORMORE:
5335 case XML_RELAXNG_OPTIONAL:
5336 case XML_RELAXNG_CHOICE:
5337 case XML_RELAXNG_GROUP:
5338 case XML_RELAXNG_INTERLEAVE:
5339 if (last == NULL) {
5340 ret->content = last = cur;
5341 } else {
5342 if ((last->type == XML_RELAXNG_ELEMENT) &&
5343 (ret->content == last)) {
5344 ret->content = xmlRelaxNGNewDefine(ctxt, node);
5345 if (ret->content != NULL) {
5346 ret->content->type = XML_RELAXNG_GROUP;
5347 ret->content->content = last;
5348 } else {
5349 ret->content = last;
5350 }
5351 }
5352 last->next = cur;
5353 last = cur;
5354 }
5355 break;
5356 case XML_RELAXNG_ATTRIBUTE:
5357 cur->next = ret->attrs;
5358 ret->attrs = cur;
5359 break;
5360 case XML_RELAXNG_START:
5361 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5362 "RNG Internal error, start found in element\n",
5363 NULL, NULL);
5364 break;
5365 case XML_RELAXNG_PARAM:
5366 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5367 "RNG Internal error, param found in element\n",
5368 NULL, NULL);
5369 break;
5370 case XML_RELAXNG_EXCEPT:
5371 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5372 "RNG Internal error, except found in element\n",
5373 NULL, NULL);
5374 break;
5375 case XML_RELAXNG_NOOP:
5376 xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5377 "RNG Internal error, noop found in element\n",
5378 NULL, NULL);
5379 break;
5380 }
5381 }
5382 child = child->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005383 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005384 ctxt->define = olddefine;
Daniel Veillard4c004142003-10-07 11:33:24 +00005385 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005386}
5387
5388/**
5389 * xmlRelaxNGParsePatterns:
5390 * @ctxt: a Relax-NG parser context
5391 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005392 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005393 *
5394 * parse the content of a RelaxNG start node.
5395 *
5396 * Returns the definition pointer or NULL in case of error.
5397 */
5398static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005399xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
Daniel Veillard4c004142003-10-07 11:33:24 +00005400 int group)
5401{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005402 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005403
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005404 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005405 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005406 if (IS_RELAXNG(nodes, "element")) {
5407 cur = xmlRelaxNGParseElement(ctxt, nodes);
5408 if (def == NULL) {
5409 def = last = cur;
5410 } else {
5411 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5412 (def == last)) {
5413 def = xmlRelaxNGNewDefine(ctxt, nodes);
5414 def->type = XML_RELAXNG_GROUP;
5415 def->content = last;
5416 }
5417 last->next = cur;
5418 last = cur;
5419 }
5420 cur->parent = parent;
5421 } else {
5422 cur = xmlRelaxNGParsePattern(ctxt, nodes);
5423 if (cur != NULL) {
5424 if (def == NULL) {
5425 def = last = cur;
5426 } else {
5427 last->next = cur;
5428 last = cur;
5429 }
5430 }
5431 }
5432 nodes = nodes->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005433 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005434 return (def);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005435}
5436
5437/**
5438 * xmlRelaxNGParseStart:
5439 * @ctxt: a Relax-NG parser context
5440 * @nodes: start children nodes
5441 *
5442 * parse the content of a RelaxNG start node.
5443 *
5444 * Returns 0 in case of success, -1 in case of error
5445 */
5446static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005447xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5448{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005449 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005450 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005451
Daniel Veillardd2298792003-02-14 16:54:11 +00005452 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005453 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
5454 NULL, NULL);
5455 return (-1);
Daniel Veillardd2298792003-02-14 16:54:11 +00005456 }
5457 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005458 def = xmlRelaxNGNewDefine(ctxt, nodes);
5459 if (def == NULL)
5460 return (-1);
5461 def->type = XML_RELAXNG_EMPTY;
5462 if (nodes->children != NULL) {
5463 xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
5464 "element empty is not empty\n", NULL, NULL);
5465 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005466 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005467 def = xmlRelaxNGNewDefine(ctxt, nodes);
5468 if (def == NULL)
5469 return (-1);
5470 def->type = XML_RELAXNG_NOT_ALLOWED;
5471 if (nodes->children != NULL) {
5472 xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5473 "element notAllowed is not empty\n", NULL, NULL);
5474 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005475 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005476 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005477 }
5478 if (ctxt->grammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005479 last = ctxt->grammar->start;
5480 while (last->next != NULL)
5481 last = last->next;
5482 last->next = def;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005483 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005484 ctxt->grammar->start = def;
Daniel Veillardd2298792003-02-14 16:54:11 +00005485 }
5486 nodes = nodes->next;
5487 if (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005488 xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
5489 "start more than one children\n", NULL, NULL);
5490 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005491 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005492 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005493}
5494
5495/**
5496 * xmlRelaxNGParseGrammarContent:
5497 * @ctxt: a Relax-NG parser context
5498 * @nodes: grammar children nodes
5499 *
5500 * parse the content of a RelaxNG grammar node.
5501 *
5502 * Returns 0 in case of success, -1 in case of error
5503 */
5504static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005505xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
5506 xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005507{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005508 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005509
5510 if (nodes == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005511 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
5512 "grammar has no children\n", NULL, NULL);
5513 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005514 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005515 while (nodes != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005516 if (IS_RELAXNG(nodes, "start")) {
5517 if (nodes->children == NULL) {
5518 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
5519 "start has no children\n", NULL, NULL);
5520 } else {
5521 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5522 if (tmp != 0)
5523 ret = -1;
5524 }
5525 } else if (IS_RELAXNG(nodes, "define")) {
5526 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5527 if (tmp != 0)
5528 ret = -1;
5529 } else if (IS_RELAXNG(nodes, "include")) {
5530 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5531 if (tmp != 0)
5532 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005533 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005534 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
5535 "grammar has unexpected child %s\n", nodes->name,
5536 NULL);
5537 ret = -1;
5538 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005539 nodes = nodes->next;
5540 }
5541 return (ret);
5542}
5543
5544/**
5545 * xmlRelaxNGCheckReference:
5546 * @ref: the ref
5547 * @ctxt: a Relax-NG parser context
5548 * @name: the name associated to the defines
5549 *
5550 * Applies the 4.17. combine attribute rule for all the define
5551 * element of a given grammar using the same name.
5552 */
5553static void
5554xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
Daniel Veillard4c004142003-10-07 11:33:24 +00005555 xmlRelaxNGParserCtxtPtr ctxt,
5556 const xmlChar * name)
5557{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005558 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005559 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005560
5561 grammar = ctxt->grammar;
5562 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005563 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5564 "Internal error: no grammar in CheckReference %s\n",
5565 name, NULL);
5566 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005567 }
5568 if (ref->content != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005569 xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5570 "Internal error: reference has content in CheckReference %s\n",
5571 name, NULL);
5572 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005573 }
5574 if (grammar->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005575 def = xmlHashLookup(grammar->defs, name);
5576 if (def != NULL) {
5577 cur = ref;
5578 while (cur != NULL) {
5579 cur->content = def;
5580 cur = cur->nextHash;
5581 }
5582 } else {
5583 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5584 "Reference %s has no matching definition\n", name,
5585 NULL);
5586 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005587 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005588 xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5589 "Reference %s has no matching definition\n", name,
5590 NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005591 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005592}
5593
5594/**
5595 * xmlRelaxNGCheckCombine:
5596 * @define: the define(s) list
5597 * @ctxt: a Relax-NG parser context
5598 * @name: the name associated to the defines
5599 *
5600 * Applies the 4.17. combine attribute rule for all the define
5601 * element of a given grammar using the same name.
5602 */
5603static void
5604xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
Daniel Veillard4c004142003-10-07 11:33:24 +00005605 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name)
5606{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005607 xmlChar *combine;
5608 int choiceOrInterleave = -1;
5609 int missing = 0;
5610 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5611
5612 if (define->nextHash == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005613 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005614 cur = define;
5615 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005616 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5617 if (combine != NULL) {
5618 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5619 if (choiceOrInterleave == -1)
5620 choiceOrInterleave = 1;
5621 else if (choiceOrInterleave == 0) {
5622 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5623 "Defines for %s use both 'choice' and 'interleave'\n",
5624 name, NULL);
5625 }
5626 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5627 if (choiceOrInterleave == -1)
5628 choiceOrInterleave = 0;
5629 else if (choiceOrInterleave == 1) {
5630 xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5631 "Defines for %s use both 'choice' and 'interleave'\n",
5632 name, NULL);
5633 }
5634 } else {
5635 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
5636 "Defines for %s use unknown combine value '%s''\n",
5637 name, combine);
5638 }
5639 xmlFree(combine);
5640 } else {
5641 if (missing == 0)
5642 missing = 1;
5643 else {
5644 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
5645 "Some defines for %s needs the combine attribute\n",
5646 name, NULL);
5647 }
5648 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005649
Daniel Veillard4c004142003-10-07 11:33:24 +00005650 cur = cur->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005651 }
5652#ifdef DEBUG
5653 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005654 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5655 name, choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005656#endif
5657 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005658 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005659 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005660 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005661 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005662 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005663 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005664 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005665 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005666 tmp = define;
5667 last = NULL;
5668 while (tmp != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005669 if (tmp->content != NULL) {
5670 if (tmp->content->next != NULL) {
5671 /*
5672 * we need first to create a wrapper.
5673 */
5674 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5675 if (tmp2 == NULL)
5676 break;
5677 tmp2->type = XML_RELAXNG_GROUP;
5678 tmp2->content = tmp->content;
5679 } else {
5680 tmp2 = tmp->content;
5681 }
5682 if (last == NULL) {
5683 cur->content = tmp2;
5684 } else {
5685 last->next = tmp2;
5686 }
5687 last = tmp2;
5688 }
5689 tmp->content = cur;
5690 tmp = tmp->nextHash;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005691 }
5692 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005693 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005694 if (ctxt->interleaves == NULL)
5695 ctxt->interleaves = xmlHashCreate(10);
5696 if (ctxt->interleaves == NULL) {
5697 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5698 "Failed to create interleaves hash table\n", NULL,
5699 NULL);
5700 } else {
5701 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005702
Daniel Veillard4c004142003-10-07 11:33:24 +00005703 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5704 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5705 0) {
5706 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5707 "Failed to add %s to hash table\n",
5708 (const xmlChar *) tmpname, NULL);
5709 }
5710 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005711 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005712}
5713
5714/**
5715 * xmlRelaxNGCombineStart:
5716 * @ctxt: a Relax-NG parser context
5717 * @grammar: the grammar
5718 *
5719 * Applies the 4.17. combine rule for all the start
5720 * element of a given grammar.
5721 */
5722static void
5723xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00005724 xmlRelaxNGGrammarPtr grammar)
5725{
Daniel Veillard6eadf632003-01-23 18:29:16 +00005726 xmlRelaxNGDefinePtr starts;
5727 xmlChar *combine;
5728 int choiceOrInterleave = -1;
5729 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005730 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005731
Daniel Veillard2df2de22003-02-17 23:34:33 +00005732 starts = grammar->start;
5733 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00005734 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005735 cur = starts;
5736 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005737 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5738 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5739 combine = NULL;
5740 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
5741 "Internal error: start element not found\n", NULL,
5742 NULL);
5743 } else {
5744 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5745 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005746
Daniel Veillard4c004142003-10-07 11:33:24 +00005747 if (combine != NULL) {
5748 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5749 if (choiceOrInterleave == -1)
5750 choiceOrInterleave = 1;
5751 else if (choiceOrInterleave == 0) {
5752 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5753 "<start> use both 'choice' and 'interleave'\n",
5754 NULL, NULL);
5755 }
5756 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5757 if (choiceOrInterleave == -1)
5758 choiceOrInterleave = 0;
5759 else if (choiceOrInterleave == 1) {
5760 xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5761 "<start> use both 'choice' and 'interleave'\n",
5762 NULL, NULL);
5763 }
5764 } else {
5765 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
5766 "<start> uses unknown combine value '%s''\n",
5767 combine, NULL);
5768 }
5769 xmlFree(combine);
5770 } else {
5771 if (missing == 0)
5772 missing = 1;
5773 else {
5774 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
5775 "Some <start> element miss the combine attribute\n",
5776 NULL, NULL);
5777 }
5778 }
5779
5780 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005781 }
5782#ifdef DEBUG
5783 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00005784 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5785 choiceOrInterleave);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005786#endif
5787 if (choiceOrInterleave == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +00005788 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005789 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005790 if (cur == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00005791 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005792 if (choiceOrInterleave == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00005793 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005794 else
Daniel Veillard4c004142003-10-07 11:33:24 +00005795 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005796 cur->content = grammar->start;
5797 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005798 if (choiceOrInterleave == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005799 if (ctxt->interleaves == NULL)
5800 ctxt->interleaves = xmlHashCreate(10);
5801 if (ctxt->interleaves == NULL) {
5802 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5803 "Failed to create interleaves hash table\n", NULL,
5804 NULL);
5805 } else {
5806 char tmpname[32];
Daniel Veillardfd573f12003-03-16 17:52:32 +00005807
Daniel Veillard4c004142003-10-07 11:33:24 +00005808 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5809 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5810 0) {
5811 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5812 "Failed to add %s to hash table\n",
5813 (const xmlChar *) tmpname, NULL);
5814 }
5815 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005816 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005817}
5818
5819/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005820 * xmlRelaxNGCheckCycles:
5821 * @ctxt: a Relax-NG parser context
5822 * @nodes: grammar children nodes
5823 * @depth: the counter
5824 *
5825 * Check for cycles.
5826 *
5827 * Returns 0 if check passed, and -1 in case of error
5828 */
5829static int
Daniel Veillard4c004142003-10-07 11:33:24 +00005830xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5831 xmlRelaxNGDefinePtr cur, int depth)
5832{
Daniel Veillardd4310742003-02-18 21:12:46 +00005833 int ret = 0;
5834
5835 while ((ret == 0) && (cur != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005836 if ((cur->type == XML_RELAXNG_REF) ||
5837 (cur->type == XML_RELAXNG_PARENTREF)) {
5838 if (cur->depth == -1) {
5839 cur->depth = depth;
5840 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5841 cur->depth = -2;
5842 } else if (depth == cur->depth) {
5843 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
5844 "Detected a cycle in %s references\n",
5845 cur->name, NULL);
5846 return (-1);
5847 }
5848 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5849 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5850 } else {
5851 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5852 }
5853 cur = cur->next;
Daniel Veillardd4310742003-02-18 21:12:46 +00005854 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005855 return (ret);
Daniel Veillardd4310742003-02-18 21:12:46 +00005856}
5857
5858/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005859 * xmlRelaxNGTryUnlink:
5860 * @ctxt: a Relax-NG parser context
5861 * @cur: the definition to unlink
5862 * @parent: the parent definition
5863 * @prev: the previous sibling definition
5864 *
5865 * Try to unlink a definition. If not possble make it a NOOP
5866 *
5867 * Returns the new prev definition
5868 */
5869static xmlRelaxNGDefinePtr
Daniel Veillard4c004142003-10-07 11:33:24 +00005870xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5871 xmlRelaxNGDefinePtr cur,
5872 xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
5873{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005874 if (prev != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005875 prev->next = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005876 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00005877 if (parent != NULL) {
5878 if (parent->content == cur)
5879 parent->content = cur->next;
5880 else if (parent->attrs == cur)
5881 parent->attrs = cur->next;
5882 else if (parent->nameClass == cur)
5883 parent->nameClass = cur->next;
5884 } else {
5885 cur->type = XML_RELAXNG_NOOP;
5886 prev = cur;
5887 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005888 }
Daniel Veillard4c004142003-10-07 11:33:24 +00005889 return (prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005890}
5891
5892/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005893 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005894 * @ctxt: a Relax-NG parser context
5895 * @nodes: grammar children nodes
5896 *
5897 * Check for simplification of empty and notAllowed
5898 */
5899static void
Daniel Veillard4c004142003-10-07 11:33:24 +00005900xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5901 xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
5902{
Daniel Veillardfd573f12003-03-16 17:52:32 +00005903 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005904
Daniel Veillardfd573f12003-03-16 17:52:32 +00005905 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00005906 if ((cur->type == XML_RELAXNG_REF) ||
5907 (cur->type == XML_RELAXNG_PARENTREF)) {
5908 if (cur->depth != -3) {
5909 cur->depth = -3;
5910 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5911 }
5912 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5913 cur->parent = parent;
5914 if ((parent != NULL) &&
5915 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5916 (parent->type == XML_RELAXNG_LIST) ||
5917 (parent->type == XML_RELAXNG_GROUP) ||
5918 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5919 (parent->type == XML_RELAXNG_ONEORMORE) ||
5920 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5921 parent->type = XML_RELAXNG_NOT_ALLOWED;
5922 break;
5923 }
5924 if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
5925 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5926 } else
5927 prev = cur;
5928 } else if (cur->type == XML_RELAXNG_EMPTY) {
5929 cur->parent = parent;
5930 if ((parent != NULL) &&
5931 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5932 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5933 parent->type = XML_RELAXNG_EMPTY;
5934 break;
5935 }
5936 if ((parent != NULL) &&
5937 ((parent->type == XML_RELAXNG_GROUP) ||
5938 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5939 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5940 } else
5941 prev = cur;
5942 } else {
5943 cur->parent = parent;
5944 if (cur->content != NULL)
5945 xmlRelaxNGSimplify(ctxt, cur->content, cur);
5946 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
5947 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5948 if (cur->nameClass != NULL)
5949 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5950 /*
5951 * On Elements, try to move attribute only generating rules on
5952 * the attrs rules.
5953 */
5954 if (cur->type == XML_RELAXNG_ELEMENT) {
5955 int attronly;
5956 xmlRelaxNGDefinePtr tmp, pre;
Daniel Veillardce192eb2003-04-16 15:58:05 +00005957
Daniel Veillard4c004142003-10-07 11:33:24 +00005958 while (cur->content != NULL) {
5959 attronly =
5960 xmlRelaxNGGenerateAttributes(ctxt, cur->content);
5961 if (attronly == 1) {
5962 /*
5963 * migrate cur->content to attrs
5964 */
5965 tmp = cur->content;
5966 cur->content = tmp->next;
5967 tmp->next = cur->attrs;
5968 cur->attrs = tmp;
5969 } else {
5970 /*
5971 * cur->content can generate elements or text
5972 */
5973 break;
5974 }
5975 }
5976 pre = cur->content;
5977 while ((pre != NULL) && (pre->next != NULL)) {
5978 tmp = pre->next;
5979 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
5980 if (attronly == 1) {
5981 /*
5982 * migrate tmp to attrs
5983 */
5984 pre->next = tmp->next;
5985 tmp->next = cur->attrs;
5986 cur->attrs = tmp;
5987 } else {
5988 pre = tmp;
5989 }
5990 }
5991 }
5992 /*
5993 * This may result in a simplification
5994 */
5995 if ((cur->type == XML_RELAXNG_GROUP) ||
5996 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5997 if (cur->content == NULL)
5998 cur->type = XML_RELAXNG_EMPTY;
5999 else if (cur->content->next == NULL) {
6000 if ((parent == NULL) && (prev == NULL)) {
6001 cur->type = XML_RELAXNG_NOOP;
6002 } else if (prev == NULL) {
6003 parent->content = cur->content;
6004 cur->content->next = cur->next;
6005 cur = cur->content;
6006 } else {
6007 cur->content->next = cur->next;
6008 prev->next = cur->content;
6009 cur = cur->content;
6010 }
6011 }
6012 }
6013 /*
6014 * the current node may have been transformed back
6015 */
6016 if ((cur->type == XML_RELAXNG_EXCEPT) &&
6017 (cur->content != NULL) &&
6018 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
6019 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6020 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6021 if ((parent != NULL) &&
6022 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6023 (parent->type == XML_RELAXNG_LIST) ||
6024 (parent->type == XML_RELAXNG_GROUP) ||
6025 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6026 (parent->type == XML_RELAXNG_ONEORMORE) ||
6027 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6028 parent->type = XML_RELAXNG_NOT_ALLOWED;
6029 break;
6030 }
6031 if ((parent != NULL) &&
6032 (parent->type == XML_RELAXNG_CHOICE)) {
6033 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6034 } else
6035 prev = cur;
6036 } else if (cur->type == XML_RELAXNG_EMPTY) {
6037 if ((parent != NULL) &&
6038 ((parent->type == XML_RELAXNG_ONEORMORE) ||
6039 (parent->type == XML_RELAXNG_ZEROORMORE))) {
6040 parent->type = XML_RELAXNG_EMPTY;
6041 break;
6042 }
6043 if ((parent != NULL) &&
6044 ((parent->type == XML_RELAXNG_GROUP) ||
6045 (parent->type == XML_RELAXNG_INTERLEAVE) ||
6046 (parent->type == XML_RELAXNG_CHOICE))) {
6047 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6048 } else
6049 prev = cur;
6050 } else {
6051 prev = cur;
6052 }
6053 }
6054 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006055 }
6056}
6057
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006058/**
6059 * xmlRelaxNGGroupContentType:
6060 * @ct1: the first content type
6061 * @ct2: the second content type
6062 *
6063 * Try to group 2 content types
6064 *
6065 * Returns the content type
6066 */
6067static xmlRelaxNGContentType
6068xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006069 xmlRelaxNGContentType ct2)
6070{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006071 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006072 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6073 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006074 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006075 return (ct2);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006076 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
Daniel Veillard4c004142003-10-07 11:33:24 +00006077 return (ct1);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006078 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00006079 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6080 return (XML_RELAXNG_CONTENT_COMPLEX);
6081 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006082}
6083
6084/**
6085 * xmlRelaxNGMaxContentType:
6086 * @ct1: the first content type
6087 * @ct2: the second content type
6088 *
6089 * Compute the max content-type
6090 *
6091 * Returns the content type
6092 */
6093static xmlRelaxNGContentType
6094xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
Daniel Veillard4c004142003-10-07 11:33:24 +00006095 xmlRelaxNGContentType ct2)
6096{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006097 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006098 (ct2 == XML_RELAXNG_CONTENT_ERROR))
6099 return (XML_RELAXNG_CONTENT_ERROR);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006100 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006101 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6102 return (XML_RELAXNG_CONTENT_SIMPLE);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006103 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00006104 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6105 return (XML_RELAXNG_CONTENT_COMPLEX);
6106 return (XML_RELAXNG_CONTENT_EMPTY);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006107}
Daniel Veillard77648bb2003-02-20 15:03:22 +00006108
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006109/**
6110 * xmlRelaxNGCheckRules:
6111 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006112 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00006113 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00006114 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006115 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006116 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006117 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006118 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006119 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006120static xmlRelaxNGContentType
Daniel Veillard4c004142003-10-07 11:33:24 +00006121xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6122 xmlRelaxNGDefinePtr cur, int flags,
6123 xmlRelaxNGType ptype)
6124{
Daniel Veillard4c5cf702003-02-21 15:40:34 +00006125 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006126 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006127
Daniel Veillardfd573f12003-03-16 17:52:32 +00006128 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006129 ret = XML_RELAXNG_CONTENT_EMPTY;
6130 if ((cur->type == XML_RELAXNG_REF) ||
6131 (cur->type == XML_RELAXNG_PARENTREF)) {
Daniel Veillard63d68a32005-03-31 13:50:00 +00006132 /*
6133 * This should actually be caught by list//element(ref) at the
6134 * element boundaries, c.f. Bug #159968 local refs are dropped
6135 * in step 4.19.
6136 */
6137#if 0
Daniel Veillard4c004142003-10-07 11:33:24 +00006138 if (flags & XML_RELAXNG_IN_LIST) {
6139 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6140 "Found forbidden pattern list//ref\n", NULL,
6141 NULL);
6142 }
Daniel Veillard63d68a32005-03-31 13:50:00 +00006143#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00006144 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6145 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6146 "Found forbidden pattern data/except//ref\n",
6147 NULL, NULL);
6148 }
6149 if (cur->depth > -4) {
6150 cur->depth = -4;
6151 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6152 flags, cur->type);
6153 cur->depth = ret - 15;
6154 } else if (cur->depth == -4) {
6155 ret = XML_RELAXNG_CONTENT_COMPLEX;
6156 } else {
6157 ret = (xmlRelaxNGContentType) (cur->depth + 15);
6158 }
6159 } else if (cur->type == XML_RELAXNG_ELEMENT) {
6160 /*
6161 * The 7.3 Attribute derivation rule for groups is plugged there
6162 */
6163 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6164 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6165 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6166 "Found forbidden pattern data/except//element(ref)\n",
6167 NULL, NULL);
6168 }
6169 if (flags & XML_RELAXNG_IN_LIST) {
6170 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6171 "Found forbidden pattern list//element(ref)\n",
6172 NULL, NULL);
6173 }
6174 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6175 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6176 "Found forbidden pattern attribute//element(ref)\n",
6177 NULL, NULL);
6178 }
6179 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6180 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6181 "Found forbidden pattern attribute//element(ref)\n",
6182 NULL, NULL);
6183 }
6184 /*
6185 * reset since in the simple form elements are only child
6186 * of grammar/define
6187 */
6188 nflags = 0;
6189 ret =
6190 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6191 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6192 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6193 "Element %s attributes have a content type error\n",
6194 cur->name, NULL);
6195 }
6196 ret =
6197 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6198 cur->type);
6199 if (ret == XML_RELAXNG_CONTENT_ERROR) {
6200 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6201 "Element %s has a content type error\n",
6202 cur->name, NULL);
6203 } else {
6204 ret = XML_RELAXNG_CONTENT_COMPLEX;
6205 }
6206 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6207 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6208 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6209 "Found forbidden pattern attribute//attribute\n",
6210 NULL, NULL);
6211 }
6212 if (flags & XML_RELAXNG_IN_LIST) {
6213 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6214 "Found forbidden pattern list//attribute\n",
6215 NULL, NULL);
6216 }
6217 if (flags & XML_RELAXNG_IN_OOMGROUP) {
6218 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6219 "Found forbidden pattern oneOrMore//group//attribute\n",
6220 NULL, NULL);
6221 }
6222 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6223 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6224 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6225 NULL, NULL);
6226 }
6227 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6228 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6229 "Found forbidden pattern data/except//attribute\n",
6230 NULL, NULL);
6231 }
6232 if (flags & XML_RELAXNG_IN_START) {
6233 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6234 "Found forbidden pattern start//attribute\n",
6235 NULL, NULL);
6236 }
6237 if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6238 && (cur->name == NULL)) {
6239 if (cur->ns == NULL) {
6240 xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6241 "Found anyName attribute without oneOrMore ancestor\n",
6242 NULL, NULL);
6243 } else {
6244 xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6245 "Found nsName attribute without oneOrMore ancestor\n",
6246 NULL, NULL);
6247 }
6248 }
6249 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6250 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6251 ret = XML_RELAXNG_CONTENT_EMPTY;
6252 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6253 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6254 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6255 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6256 "Found forbidden pattern data/except//oneOrMore\n",
6257 NULL, NULL);
6258 }
6259 if (flags & XML_RELAXNG_IN_START) {
6260 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6261 "Found forbidden pattern start//oneOrMore\n",
6262 NULL, NULL);
6263 }
6264 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6265 ret =
6266 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6267 cur->type);
6268 ret = xmlRelaxNGGroupContentType(ret, ret);
6269 } else if (cur->type == XML_RELAXNG_LIST) {
6270 if (flags & XML_RELAXNG_IN_LIST) {
6271 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6272 "Found forbidden pattern list//list\n", NULL,
6273 NULL);
6274 }
6275 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6276 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6277 "Found forbidden pattern data/except//list\n",
6278 NULL, NULL);
6279 }
6280 if (flags & XML_RELAXNG_IN_START) {
6281 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6282 "Found forbidden pattern start//list\n", NULL,
6283 NULL);
6284 }
6285 nflags = flags | XML_RELAXNG_IN_LIST;
6286 ret =
6287 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6288 cur->type);
6289 } else if (cur->type == XML_RELAXNG_GROUP) {
6290 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6291 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6292 "Found forbidden pattern data/except//group\n",
6293 NULL, NULL);
6294 }
6295 if (flags & XML_RELAXNG_IN_START) {
6296 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6297 "Found forbidden pattern start//group\n", NULL,
6298 NULL);
6299 }
6300 if (flags & XML_RELAXNG_IN_ONEORMORE)
6301 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6302 else
6303 nflags = flags;
6304 ret =
6305 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6306 cur->type);
6307 /*
6308 * The 7.3 Attribute derivation rule for groups is plugged there
6309 */
6310 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6311 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6312 if (flags & XML_RELAXNG_IN_LIST) {
6313 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6314 "Found forbidden pattern list//interleave\n",
6315 NULL, NULL);
6316 }
6317 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6318 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6319 "Found forbidden pattern data/except//interleave\n",
6320 NULL, NULL);
6321 }
6322 if (flags & XML_RELAXNG_IN_START) {
6323 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6324 "Found forbidden pattern start//interleave\n",
6325 NULL, NULL);
6326 }
6327 if (flags & XML_RELAXNG_IN_ONEORMORE)
6328 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6329 else
6330 nflags = flags;
6331 ret =
6332 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6333 cur->type);
6334 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6335 if ((cur->parent != NULL) &&
6336 (cur->parent->type == XML_RELAXNG_DATATYPE))
6337 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6338 else
6339 nflags = flags;
6340 ret =
6341 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6342 cur->type);
6343 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6344 if (flags & XML_RELAXNG_IN_START) {
6345 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6346 "Found forbidden pattern start//data\n", NULL,
6347 NULL);
6348 }
6349 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6350 ret = XML_RELAXNG_CONTENT_SIMPLE;
6351 } else if (cur->type == XML_RELAXNG_VALUE) {
6352 if (flags & XML_RELAXNG_IN_START) {
6353 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6354 "Found forbidden pattern start//value\n", NULL,
6355 NULL);
6356 }
6357 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6358 ret = XML_RELAXNG_CONTENT_SIMPLE;
6359 } else if (cur->type == XML_RELAXNG_TEXT) {
6360 if (flags & XML_RELAXNG_IN_LIST) {
6361 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6362 "Found forbidden pattern list//text\n", NULL,
6363 NULL);
6364 }
6365 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6366 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6367 "Found forbidden pattern data/except//text\n",
6368 NULL, NULL);
6369 }
6370 if (flags & XML_RELAXNG_IN_START) {
6371 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6372 "Found forbidden pattern start//text\n", NULL,
6373 NULL);
6374 }
6375 ret = XML_RELAXNG_CONTENT_COMPLEX;
6376 } else if (cur->type == XML_RELAXNG_EMPTY) {
6377 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6378 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6379 "Found forbidden pattern data/except//empty\n",
6380 NULL, NULL);
6381 }
6382 if (flags & XML_RELAXNG_IN_START) {
6383 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6384 "Found forbidden pattern start//empty\n", NULL,
6385 NULL);
6386 }
6387 ret = XML_RELAXNG_CONTENT_EMPTY;
6388 } else if (cur->type == XML_RELAXNG_CHOICE) {
6389 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6390 ret =
6391 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6392 } else {
6393 ret =
6394 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6395 }
6396 cur = cur->next;
6397 if (ptype == XML_RELAXNG_GROUP) {
6398 val = xmlRelaxNGGroupContentType(val, ret);
6399 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6400 tmp = xmlRelaxNGGroupContentType(val, ret);
6401 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6402 tmp = xmlRelaxNGMaxContentType(val, ret);
6403 } else if (ptype == XML_RELAXNG_CHOICE) {
6404 val = xmlRelaxNGMaxContentType(val, ret);
6405 } else if (ptype == XML_RELAXNG_LIST) {
6406 val = XML_RELAXNG_CONTENT_SIMPLE;
6407 } else if (ptype == XML_RELAXNG_EXCEPT) {
6408 if (ret == XML_RELAXNG_CONTENT_ERROR)
6409 val = XML_RELAXNG_CONTENT_ERROR;
6410 else
6411 val = XML_RELAXNG_CONTENT_SIMPLE;
6412 } else {
6413 val = xmlRelaxNGGroupContentType(val, ret);
6414 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006415
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006416 }
Daniel Veillard4c004142003-10-07 11:33:24 +00006417 return (val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006418}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006419
6420/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006421 * xmlRelaxNGParseGrammar:
6422 * @ctxt: a Relax-NG parser context
6423 * @nodes: grammar children nodes
6424 *
6425 * parse a Relax-NG <grammar> node
6426 *
6427 * Returns the internal xmlRelaxNGGrammarPtr built or
6428 * NULL in case of error
6429 */
6430static xmlRelaxNGGrammarPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006431xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6432{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006433 xmlRelaxNGGrammarPtr ret, tmp, old;
6434
Daniel Veillardc482e262003-02-26 14:48:48 +00006435#ifdef DEBUG_GRAMMAR
6436 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6437#endif
6438
Daniel Veillard6eadf632003-01-23 18:29:16 +00006439 ret = xmlRelaxNGNewGrammar(ctxt);
6440 if (ret == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006441 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006442
6443 /*
6444 * Link the new grammar in the tree
6445 */
6446 ret->parent = ctxt->grammar;
6447 if (ctxt->grammar != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006448 tmp = ctxt->grammar->children;
6449 if (tmp == NULL) {
6450 ctxt->grammar->children = ret;
6451 } else {
6452 while (tmp->next != NULL)
6453 tmp = tmp->next;
6454 tmp->next = ret;
6455 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006456 }
6457
6458 old = ctxt->grammar;
6459 ctxt->grammar = ret;
6460 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6461 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006462 if (ctxt->grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006463 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6464 "Failed to parse <grammar> content\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006465 } else if (ctxt->grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006466 xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6467 "Element <grammar> has no <start>\n", NULL, NULL);
Daniel Veillard2df2de22003-02-17 23:34:33 +00006468 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006469
6470 /*
6471 * Apply 4.17 mergingd rules to defines and starts
6472 */
6473 xmlRelaxNGCombineStart(ctxt, ret);
6474 if (ret->defs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006475 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6476 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006477 }
6478
6479 /*
6480 * link together defines and refs in this grammar
6481 */
6482 if (ret->refs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006483 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6484 ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006485 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006486
Daniel Veillard6eadf632003-01-23 18:29:16 +00006487 ctxt->grammar = old;
Daniel Veillard4c004142003-10-07 11:33:24 +00006488 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006489}
6490
6491/**
6492 * xmlRelaxNGParseDocument:
6493 * @ctxt: a Relax-NG parser context
6494 * @node: the root node of the RelaxNG schema
6495 *
6496 * parse a Relax-NG definition resource and build an internal
6497 * xmlRelaxNG struture which can be used to validate instances.
6498 *
6499 * Returns the internal XML RelaxNG structure built or
6500 * NULL in case of error
6501 */
6502static xmlRelaxNGPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006503xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6504{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006505 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006506 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006507 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006508
6509 if ((ctxt == NULL) || (node == NULL))
6510 return (NULL);
6511
6512 schema = xmlRelaxNGNewRelaxNG(ctxt);
6513 if (schema == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006514 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006515
Daniel Veillard276be4a2003-01-24 01:03:34 +00006516 olddefine = ctxt->define;
6517 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006518 if (IS_RELAXNG(node, "grammar")) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006519 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006520 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006521 xmlRelaxNGGrammarPtr tmp, ret;
Daniel Veillardc482e262003-02-26 14:48:48 +00006522
Daniel Veillard4c004142003-10-07 11:33:24 +00006523 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6524 if (schema->topgrammar == NULL) {
6525 return (schema);
6526 }
6527 /*
6528 * Link the new grammar in the tree
6529 */
6530 ret->parent = ctxt->grammar;
6531 if (ctxt->grammar != NULL) {
6532 tmp = ctxt->grammar->children;
6533 if (tmp == NULL) {
6534 ctxt->grammar->children = ret;
6535 } else {
6536 while (tmp->next != NULL)
6537 tmp = tmp->next;
6538 tmp->next = ret;
6539 }
6540 }
6541 old = ctxt->grammar;
6542 ctxt->grammar = ret;
6543 xmlRelaxNGParseStart(ctxt, node);
6544 if (old != NULL)
6545 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006546 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006547 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006548 if (schema->topgrammar->start != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006549 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6550 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6551 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6552 while ((schema->topgrammar->start != NULL) &&
6553 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6554 (schema->topgrammar->start->next != NULL))
6555 schema->topgrammar->start =
6556 schema->topgrammar->start->content;
6557 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6558 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6559 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006560 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006561#ifdef DEBUG
6562 if (schema == NULL)
6563 xmlGenericError(xmlGenericErrorContext,
6564 "xmlRelaxNGParseDocument() failed\n");
6565#endif
6566
6567 return (schema);
6568}
6569
6570/************************************************************************
6571 * *
6572 * Reading RelaxNGs *
6573 * *
6574 ************************************************************************/
6575
6576/**
6577 * xmlRelaxNGNewParserCtxt:
6578 * @URL: the location of the schema
6579 *
6580 * Create an XML RelaxNGs parse context for that file/resource expected
6581 * to contain an XML RelaxNGs file.
6582 *
6583 * Returns the parser context or NULL in case of error
6584 */
6585xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006586xmlRelaxNGNewParserCtxt(const char *URL)
6587{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006588 xmlRelaxNGParserCtxtPtr ret;
6589
6590 if (URL == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006591 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006592
Daniel Veillard4c004142003-10-07 11:33:24 +00006593 ret =
6594 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006595 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006596 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006597 return (NULL);
6598 }
6599 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard4c004142003-10-07 11:33:24 +00006600 ret->URL = xmlStrdup((const xmlChar *) URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006601 ret->error = xmlGenericError;
6602 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006603 return (ret);
6604}
6605
6606/**
6607 * xmlRelaxNGNewMemParserCtxt:
6608 * @buffer: a pointer to a char array containing the schemas
6609 * @size: the size of the array
6610 *
6611 * Create an XML RelaxNGs parse context for that memory buffer expected
6612 * to contain an XML RelaxNGs file.
6613 *
6614 * Returns the parser context or NULL in case of error
6615 */
6616xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006617xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6618{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006619 xmlRelaxNGParserCtxtPtr ret;
6620
6621 if ((buffer == NULL) || (size <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00006622 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006623
Daniel Veillard4c004142003-10-07 11:33:24 +00006624 ret =
6625 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard6eadf632003-01-23 18:29:16 +00006626 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006627 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00006628 return (NULL);
6629 }
6630 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6631 ret->buffer = buffer;
6632 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006633 ret->error = xmlGenericError;
6634 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006635 return (ret);
6636}
6637
6638/**
Daniel Veillard33300b42003-04-17 09:09:19 +00006639 * xmlRelaxNGNewDocParserCtxt:
6640 * @doc: a preparsed document tree
6641 *
6642 * Create an XML RelaxNGs parser context for that document.
6643 * Note: since the process of compiling a RelaxNG schemas modifies the
6644 * document, the @doc parameter is duplicated internally.
6645 *
6646 * Returns the parser context or NULL in case of error
6647 */
6648xmlRelaxNGParserCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00006649xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6650{
Daniel Veillard33300b42003-04-17 09:09:19 +00006651 xmlRelaxNGParserCtxtPtr ret;
6652 xmlDocPtr copy;
6653
6654 if (doc == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006655 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006656 copy = xmlCopyDoc(doc, 1);
6657 if (copy == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006658 return (NULL);
Daniel Veillard33300b42003-04-17 09:09:19 +00006659
Daniel Veillard4c004142003-10-07 11:33:24 +00006660 ret =
6661 (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
Daniel Veillard33300b42003-04-17 09:09:19 +00006662 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006663 xmlRngPErrMemory(NULL, "building parser\n");
Daniel Veillard33300b42003-04-17 09:09:19 +00006664 return (NULL);
6665 }
6666 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6667 ret->document = copy;
Daniel Veillard42595322004-11-08 10:52:06 +00006668 ret->freedoc = 1;
Daniel Veillard33300b42003-04-17 09:09:19 +00006669 ret->userData = xmlGenericErrorContext;
6670 return (ret);
6671}
6672
6673/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006674 * xmlRelaxNGFreeParserCtxt:
6675 * @ctxt: the schema parser context
6676 *
6677 * Free the resources associated to the schema parser context
6678 */
6679void
Daniel Veillard4c004142003-10-07 11:33:24 +00006680xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6681{
Daniel Veillard6eadf632003-01-23 18:29:16 +00006682 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006683 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006684 if (ctxt->URL != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006685 xmlFree(ctxt->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006686 if (ctxt->doc != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006687 xmlRelaxNGFreeDocument(ctxt->doc);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006688 if (ctxt->interleaves != NULL)
6689 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006690 if (ctxt->documents != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006691 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006692 if (ctxt->includes != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006693 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006694 if (ctxt->docTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006695 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006696 if (ctxt->incTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00006697 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006698 if (ctxt->defTab != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006699 int i;
Daniel Veillard419a7682003-02-03 23:22:49 +00006700
Daniel Veillard4c004142003-10-07 11:33:24 +00006701 for (i = 0; i < ctxt->defNr; i++)
6702 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6703 xmlFree(ctxt->defTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006704 }
Daniel Veillard42595322004-11-08 10:52:06 +00006705 if ((ctxt->document != NULL) && (ctxt->freedoc))
6706 xmlFreeDoc(ctxt->document);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006707 xmlFree(ctxt);
6708}
6709
Daniel Veillard6eadf632003-01-23 18:29:16 +00006710/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006711 * xmlRelaxNGNormExtSpace:
6712 * @value: a value
6713 *
6714 * Removes the leading and ending spaces of the value
6715 * The string is modified "in situ"
6716 */
6717static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006718xmlRelaxNGNormExtSpace(xmlChar * value)
6719{
Daniel Veillardd2298792003-02-14 16:54:11 +00006720 xmlChar *start = value;
6721 xmlChar *cur = value;
Daniel Veillardd2298792003-02-14 16:54:11 +00006722
Daniel Veillard4c004142003-10-07 11:33:24 +00006723 if (value == NULL)
6724 return;
6725
William M. Brack76e95df2003-10-18 16:20:14 +00006726 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006727 cur++;
Daniel Veillardd2298792003-02-14 16:54:11 +00006728 if (cur == start) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006729 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006730 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006731 cur++;
6732 if (*cur == 0)
6733 return;
6734 start = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006735 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006736 cur++;
6737 if (*cur == 0) {
6738 *start = 0;
6739 return;
6740 }
6741 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006742 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00006743 do {
William M. Brack76e95df2003-10-18 16:20:14 +00006744 while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
Daniel Veillard4c004142003-10-07 11:33:24 +00006745 *start++ = *cur++;
6746 if (*cur == 0) {
6747 *start = 0;
6748 return;
6749 }
6750 /* don't try to normalize the inner spaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006751 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00006752 cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006753 if (*cur == 0) {
6754 *start = 0;
6755 return;
6756 }
Daniel Veillard4aede2e2003-10-17 12:43:59 +00006757 *start++ = *cur++;
Daniel Veillard4c004142003-10-07 11:33:24 +00006758 } while (1);
Daniel Veillardd2298792003-02-14 16:54:11 +00006759 }
6760}
6761
6762/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +00006763 * xmlRelaxNGCleanupAttributes:
Daniel Veillardd2298792003-02-14 16:54:11 +00006764 * @ctxt: a Relax-NG parser context
6765 * @node: a Relax-NG node
6766 *
6767 * Check all the attributes on the given node
6768 */
6769static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006770xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6771{
Daniel Veillardd2298792003-02-14 16:54:11 +00006772 xmlAttrPtr cur, next;
6773
6774 cur = node->properties;
6775 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006776 next = cur->next;
6777 if ((cur->ns == NULL) ||
6778 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6779 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6780 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6781 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6782 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6783 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6784 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
6785 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6786 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6787 "Attribute %s is not allowed on %s\n",
6788 cur->name, node->name);
6789 }
6790 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6791 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6792 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6793 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6794 "Attribute %s is not allowed on %s\n",
6795 cur->name, node->name);
6796 }
6797 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6798 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6799 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6800 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6801 "Attribute %s is not allowed on %s\n",
6802 cur->name, node->name);
6803 }
6804 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6805 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6806 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6807 xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6808 "Attribute %s is not allowed on %s\n",
6809 cur->name, node->name);
6810 }
6811 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6812 xmlChar *val;
6813 xmlURIPtr uri;
Daniel Veillardd2298792003-02-14 16:54:11 +00006814
Daniel Veillard4c004142003-10-07 11:33:24 +00006815 val = xmlNodeListGetString(node->doc, cur->children, 1);
6816 if (val != NULL) {
6817 if (val[0] != 0) {
6818 uri = xmlParseURI((const char *) val);
6819 if (uri == NULL) {
6820 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
6821 "Attribute %s contains invalid URI %s\n",
6822 cur->name, val);
6823 } else {
6824 if (uri->scheme == NULL) {
6825 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
6826 "Attribute %s URI %s is not absolute\n",
6827 cur->name, val);
6828 }
6829 if (uri->fragment != NULL) {
6830 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
6831 "Attribute %s URI %s has a fragment ID\n",
6832 cur->name, val);
6833 }
6834 xmlFreeURI(uri);
6835 }
6836 }
6837 xmlFree(val);
6838 }
6839 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6840 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
6841 "Unknown attribute %s on %s\n", cur->name,
6842 node->name);
6843 }
6844 }
6845 cur = next;
Daniel Veillardd2298792003-02-14 16:54:11 +00006846 }
6847}
6848
6849/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006850 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006851 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006852 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006853 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006854 * Cleanup the subtree from unwanted nodes for parsing, resolve
6855 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006856 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006857static void
Daniel Veillard4c004142003-10-07 11:33:24 +00006858xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
6859{
Daniel Veillardc5312d72003-02-21 17:14:10 +00006860 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006861
Daniel Veillard6eadf632003-01-23 18:29:16 +00006862 delete = NULL;
6863 cur = root;
6864 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00006865 if (delete != NULL) {
6866 xmlUnlinkNode(delete);
6867 xmlFreeNode(delete);
6868 delete = NULL;
6869 }
6870 if (cur->type == XML_ELEMENT_NODE) {
6871 /*
6872 * Simplification 4.1. Annotations
6873 */
6874 if ((cur->ns == NULL) ||
6875 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6876 if ((cur->parent != NULL) &&
6877 (cur->parent->type == XML_ELEMENT_NODE) &&
6878 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6879 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6880 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6881 xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
6882 "element %s doesn't allow foreign elements\n",
6883 cur->parent->name, NULL);
6884 }
6885 delete = cur;
6886 goto skip_children;
6887 } else {
6888 xmlRelaxNGCleanupAttributes(ctxt, cur);
6889 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6890 xmlChar *href, *ns, *base, *URL;
6891 xmlRelaxNGDocumentPtr docu;
6892 xmlNodePtr tmp;
Daniel Veillard6dc91962004-03-22 19:10:02 +00006893 xmlURIPtr uri;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006894
Daniel Veillard4c004142003-10-07 11:33:24 +00006895 ns = xmlGetProp(cur, BAD_CAST "ns");
6896 if (ns == NULL) {
6897 tmp = cur->parent;
6898 while ((tmp != NULL) &&
6899 (tmp->type == XML_ELEMENT_NODE)) {
6900 ns = xmlGetProp(tmp, BAD_CAST "ns");
6901 if (ns != NULL)
6902 break;
6903 tmp = tmp->parent;
6904 }
6905 }
6906 href = xmlGetProp(cur, BAD_CAST "href");
6907 if (href == NULL) {
6908 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6909 "xmlRelaxNGParse: externalRef has no href attribute\n",
6910 NULL, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006911 if (ns != NULL)
6912 xmlFree(ns);
Daniel Veillard4c004142003-10-07 11:33:24 +00006913 delete = cur;
6914 goto skip_children;
6915 }
Daniel Veillard6dc91962004-03-22 19:10:02 +00006916 uri = xmlParseURI((const char *) href);
6917 if (uri == NULL) {
6918 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6919 "Incorrect URI for externalRef %s\n",
6920 href, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006921 if (ns != NULL)
6922 xmlFree(ns);
Daniel Veillard6dc91962004-03-22 19:10:02 +00006923 if (href != NULL)
6924 xmlFree(href);
6925 delete = cur;
6926 goto skip_children;
6927 }
6928 if (uri->fragment != NULL) {
6929 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6930 "Fragment forbidden in URI for externalRef %s\n",
6931 href, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006932 if (ns != NULL)
6933 xmlFree(ns);
Daniel Veillard6dc91962004-03-22 19:10:02 +00006934 xmlFreeURI(uri);
6935 if (href != NULL)
6936 xmlFree(href);
6937 delete = cur;
6938 goto skip_children;
6939 }
6940 xmlFreeURI(uri);
Daniel Veillard4c004142003-10-07 11:33:24 +00006941 base = xmlNodeGetBase(cur->doc, cur);
6942 URL = xmlBuildURI(href, base);
6943 if (URL == NULL) {
6944 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6945 "Failed to compute URL for externalRef %s\n",
6946 href, NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006947 if (ns != NULL)
6948 xmlFree(ns);
Daniel Veillard4c004142003-10-07 11:33:24 +00006949 if (href != NULL)
6950 xmlFree(href);
6951 if (base != NULL)
6952 xmlFree(base);
6953 delete = cur;
6954 goto skip_children;
6955 }
6956 if (href != NULL)
6957 xmlFree(href);
6958 if (base != NULL)
6959 xmlFree(base);
6960 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6961 if (docu == NULL) {
6962 xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
6963 "Failed to load externalRef %s\n", URL,
6964 NULL);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00006965 if (ns != NULL)
6966 xmlFree(ns);
Daniel Veillard4c004142003-10-07 11:33:24 +00006967 xmlFree(URL);
6968 delete = cur;
6969 goto skip_children;
6970 }
6971 if (ns != NULL)
6972 xmlFree(ns);
6973 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00006974 cur->psvi = docu;
Daniel Veillard4c004142003-10-07 11:33:24 +00006975 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6976 xmlChar *href, *ns, *base, *URL;
6977 xmlRelaxNGIncludePtr incl;
6978 xmlNodePtr tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006979
Daniel Veillard4c004142003-10-07 11:33:24 +00006980 href = xmlGetProp(cur, BAD_CAST "href");
6981 if (href == NULL) {
6982 xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6983 "xmlRelaxNGParse: include has no href attribute\n",
6984 NULL, NULL);
6985 delete = cur;
6986 goto skip_children;
6987 }
6988 base = xmlNodeGetBase(cur->doc, cur);
6989 URL = xmlBuildURI(href, base);
6990 if (URL == NULL) {
6991 xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6992 "Failed to compute URL for include %s\n",
6993 href, NULL);
6994 if (href != NULL)
6995 xmlFree(href);
6996 if (base != NULL)
6997 xmlFree(base);
6998 delete = cur;
6999 goto skip_children;
7000 }
7001 if (href != NULL)
7002 xmlFree(href);
7003 if (base != NULL)
7004 xmlFree(base);
7005 ns = xmlGetProp(cur, BAD_CAST "ns");
7006 if (ns == NULL) {
7007 tmp = cur->parent;
7008 while ((tmp != NULL) &&
7009 (tmp->type == XML_ELEMENT_NODE)) {
7010 ns = xmlGetProp(tmp, BAD_CAST "ns");
7011 if (ns != NULL)
7012 break;
7013 tmp = tmp->parent;
7014 }
7015 }
7016 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
7017 if (ns != NULL)
7018 xmlFree(ns);
7019 if (incl == NULL) {
7020 xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
7021 "Failed to load include %s\n", URL,
7022 NULL);
7023 xmlFree(URL);
7024 delete = cur;
7025 goto skip_children;
7026 }
7027 xmlFree(URL);
Daniel Veillard807daf82004-02-22 22:13:27 +00007028 cur->psvi = incl;
Daniel Veillard4c004142003-10-07 11:33:24 +00007029 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7030 (xmlStrEqual(cur->name, BAD_CAST "attribute")))
7031 {
7032 xmlChar *name, *ns;
7033 xmlNodePtr text = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007034
Daniel Veillard4c004142003-10-07 11:33:24 +00007035 /*
7036 * Simplification 4.8. name attribute of element
7037 * and attribute elements
7038 */
7039 name = xmlGetProp(cur, BAD_CAST "name");
7040 if (name != NULL) {
7041 if (cur->children == NULL) {
7042 text =
7043 xmlNewChild(cur, cur->ns, BAD_CAST "name",
7044 name);
7045 } else {
7046 xmlNodePtr node;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007047
Daniel Veillard03a53c32004-10-26 16:06:51 +00007048 node = xmlNewDocNode(cur->doc, cur->ns,
7049 BAD_CAST "name", NULL);
Daniel Veillard4c004142003-10-07 11:33:24 +00007050 if (node != NULL) {
7051 xmlAddPrevSibling(cur->children, node);
7052 text = xmlNewText(name);
7053 xmlAddChild(node, text);
7054 text = node;
7055 }
7056 }
7057 if (text == NULL) {
7058 xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7059 "Failed to create a name %s element\n",
7060 name, NULL);
7061 }
7062 xmlUnsetProp(cur, BAD_CAST "name");
7063 xmlFree(name);
7064 ns = xmlGetProp(cur, BAD_CAST "ns");
7065 if (ns != NULL) {
7066 if (text != NULL) {
7067 xmlSetProp(text, BAD_CAST "ns", ns);
7068 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7069 }
7070 xmlFree(ns);
7071 } else if (xmlStrEqual(cur->name,
7072 BAD_CAST "attribute")) {
7073 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7074 }
7075 }
7076 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7077 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7078 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
7079 /*
7080 * Simplification 4.8. name attribute of element
7081 * and attribute elements
7082 */
7083 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7084 xmlNodePtr node;
7085 xmlChar *ns = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007086
Daniel Veillard4c004142003-10-07 11:33:24 +00007087 node = cur->parent;
7088 while ((node != NULL) &&
7089 (node->type == XML_ELEMENT_NODE)) {
7090 ns = xmlGetProp(node, BAD_CAST "ns");
7091 if (ns != NULL) {
7092 break;
7093 }
7094 node = node->parent;
7095 }
7096 if (ns == NULL) {
7097 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7098 } else {
7099 xmlSetProp(cur, BAD_CAST "ns", ns);
7100 xmlFree(ns);
7101 }
7102 }
7103 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7104 xmlChar *name, *local, *prefix;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007105
Daniel Veillard4c004142003-10-07 11:33:24 +00007106 /*
7107 * Simplification: 4.10. QNames
7108 */
7109 name = xmlNodeGetContent(cur);
7110 if (name != NULL) {
7111 local = xmlSplitQName2(name, &prefix);
7112 if (local != NULL) {
7113 xmlNsPtr ns;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007114
Daniel Veillard4c004142003-10-07 11:33:24 +00007115 ns = xmlSearchNs(cur->doc, cur, prefix);
7116 if (ns == NULL) {
7117 xmlRngPErr(ctxt, cur,
7118 XML_RNGP_PREFIX_UNDEFINED,
7119 "xmlRelaxNGParse: no namespace for prefix %s\n",
7120 prefix, NULL);
7121 } else {
7122 xmlSetProp(cur, BAD_CAST "ns",
7123 ns->href);
7124 xmlNodeSetContent(cur, local);
7125 }
7126 xmlFree(local);
7127 xmlFree(prefix);
7128 }
7129 xmlFree(name);
7130 }
7131 }
7132 /*
7133 * 4.16
7134 */
7135 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7136 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7137 xmlRngPErr(ctxt, cur,
7138 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7139 "Found nsName/except//nsName forbidden construct\n",
7140 NULL, NULL);
7141 }
7142 }
7143 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7144 (cur != root)) {
7145 int oldflags = ctxt->flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007146
Daniel Veillard4c004142003-10-07 11:33:24 +00007147 /*
7148 * 4.16
7149 */
7150 if ((cur->parent != NULL) &&
7151 (xmlStrEqual
7152 (cur->parent->name, BAD_CAST "anyName"))) {
7153 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7154 xmlRelaxNGCleanupTree(ctxt, cur);
7155 ctxt->flags = oldflags;
7156 goto skip_children;
7157 } else if ((cur->parent != NULL) &&
7158 (xmlStrEqual
7159 (cur->parent->name, BAD_CAST "nsName"))) {
7160 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7161 xmlRelaxNGCleanupTree(ctxt, cur);
7162 ctxt->flags = oldflags;
7163 goto skip_children;
7164 }
7165 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7166 /*
7167 * 4.16
7168 */
7169 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7170 xmlRngPErr(ctxt, cur,
7171 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7172 "Found anyName/except//anyName forbidden construct\n",
7173 NULL, NULL);
7174 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7175 xmlRngPErr(ctxt, cur,
7176 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7177 "Found nsName/except//anyName forbidden construct\n",
7178 NULL, NULL);
7179 }
7180 }
7181 /*
7182 * Thisd is not an else since "include" is transformed
7183 * into a div
7184 */
7185 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7186 xmlChar *ns;
7187 xmlNodePtr child, ins, tmp;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007188
Daniel Veillard4c004142003-10-07 11:33:24 +00007189 /*
7190 * implements rule 4.11
7191 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00007192
Daniel Veillard4c004142003-10-07 11:33:24 +00007193 ns = xmlGetProp(cur, BAD_CAST "ns");
7194
7195 child = cur->children;
7196 ins = cur;
7197 while (child != NULL) {
7198 if (ns != NULL) {
7199 if (!xmlHasProp(child, BAD_CAST "ns")) {
7200 xmlSetProp(child, BAD_CAST "ns", ns);
7201 }
7202 }
7203 tmp = child->next;
7204 xmlUnlinkNode(child);
7205 ins = xmlAddNextSibling(ins, child);
7206 child = tmp;
7207 }
7208 if (ns != NULL)
7209 xmlFree(ns);
William M. Brack8eabb052004-06-07 14:15:54 +00007210 /*
7211 * Since we are about to delete cur, if it's nsDef is non-NULL we
7212 * need to preserve it (it contains the ns definitions for the
7213 * children we just moved). We'll just stick it on to the end
7214 * of cur->parent's list, since it's never going to be re-serialized
7215 * (bug 143738).
7216 */
7217 if (cur->nsDef != NULL) {
7218 xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
7219 while (parDef->next != NULL)
7220 parDef = parDef->next;
7221 parDef->next = cur->nsDef;
7222 cur->nsDef = NULL;
7223 }
Daniel Veillard4c004142003-10-07 11:33:24 +00007224 delete = cur;
7225 goto skip_children;
7226 }
7227 }
7228 }
7229 /*
7230 * Simplification 4.2 whitespaces
7231 */
7232 else if ((cur->type == XML_TEXT_NODE) ||
7233 (cur->type == XML_CDATA_SECTION_NODE)) {
7234 if (IS_BLANK_NODE(cur)) {
7235 if (cur->parent->type == XML_ELEMENT_NODE) {
7236 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7237 &&
7238 (!xmlStrEqual
7239 (cur->parent->name, BAD_CAST "param")))
7240 delete = cur;
7241 } else {
7242 delete = cur;
7243 goto skip_children;
7244 }
7245 }
7246 } else {
7247 delete = cur;
7248 goto skip_children;
7249 }
7250
7251 /*
7252 * Skip to next node
7253 */
7254 if (cur->children != NULL) {
7255 if ((cur->children->type != XML_ENTITY_DECL) &&
7256 (cur->children->type != XML_ENTITY_REF_NODE) &&
7257 (cur->children->type != XML_ENTITY_NODE)) {
7258 cur = cur->children;
7259 continue;
7260 }
7261 }
7262 skip_children:
7263 if (cur->next != NULL) {
7264 cur = cur->next;
7265 continue;
7266 }
7267
7268 do {
7269 cur = cur->parent;
7270 if (cur == NULL)
7271 break;
7272 if (cur == root) {
7273 cur = NULL;
7274 break;
7275 }
7276 if (cur->next != NULL) {
7277 cur = cur->next;
7278 break;
7279 }
7280 } while (cur != NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007281 }
7282 if (delete != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007283 xmlUnlinkNode(delete);
7284 xmlFreeNode(delete);
7285 delete = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007286 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00007287}
Daniel Veillard6eadf632003-01-23 18:29:16 +00007288
Daniel Veillardc5312d72003-02-21 17:14:10 +00007289/**
7290 * xmlRelaxNGCleanupDoc:
7291 * @ctxt: a Relax-NG parser context
7292 * @doc: an xmldocPtr document pointer
7293 *
7294 * Cleanup the document from unwanted nodes for parsing, resolve
7295 * Include and externalRef lookups.
7296 *
7297 * Returns the cleaned up document or NULL in case of error
7298 */
7299static xmlDocPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007300xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7301{
Daniel Veillardc5312d72003-02-21 17:14:10 +00007302 xmlNodePtr root;
7303
7304 /*
7305 * Extract the root
7306 */
7307 root = xmlDocGetRootElement(doc);
7308 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007309 xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7310 ctxt->URL, NULL);
Daniel Veillardc5312d72003-02-21 17:14:10 +00007311 return (NULL);
7312 }
7313 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillard4c004142003-10-07 11:33:24 +00007314 return (doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007315}
7316
7317/**
7318 * xmlRelaxNGParse:
7319 * @ctxt: a Relax-NG parser context
7320 *
7321 * parse a schema definition resource and build an internal
7322 * XML Shema struture which can be used to validate instances.
7323 * *WARNING* this interface is highly subject to change
7324 *
7325 * Returns the internal XML RelaxNG structure built from the resource or
7326 * NULL in case of error
7327 */
7328xmlRelaxNGPtr
7329xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7330{
7331 xmlRelaxNGPtr ret = NULL;
7332 xmlDocPtr doc;
7333 xmlNodePtr root;
7334
7335 xmlRelaxNGInitTypes();
7336
7337 if (ctxt == NULL)
7338 return (NULL);
7339
7340 /*
7341 * First step is to parse the input document into an DOM/Infoset
7342 */
7343 if (ctxt->URL != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007344 doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007345 if (doc == NULL) {
7346 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7347 "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7348 NULL);
7349 return (NULL);
7350 }
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007351 } else if (ctxt->buffer != NULL) {
Daniel Veillard87247e82004-01-13 20:42:02 +00007352 doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
Daniel Veillard4c004142003-10-07 11:33:24 +00007353 if (doc == NULL) {
7354 xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7355 "xmlRelaxNGParse: could not parse schemas\n", NULL,
7356 NULL);
7357 return (NULL);
7358 }
7359 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7360 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard33300b42003-04-17 09:09:19 +00007361 } else if (ctxt->document != NULL) {
7362 doc = ctxt->document;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007363 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007364 xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7365 "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7366 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007367 }
7368 ctxt->document = doc;
7369
7370 /*
7371 * Some preprocessing of the document content
7372 */
7373 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7374 if (doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007375 xmlFreeDoc(ctxt->document);
7376 ctxt->document = NULL;
7377 return (NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007378 }
7379
Daniel Veillard6eadf632003-01-23 18:29:16 +00007380 /*
7381 * Then do the parsing for good
7382 */
7383 root = xmlDocGetRootElement(doc);
7384 if (root == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007385 xmlRngPErr(ctxt, (xmlNodePtr) doc,
7386 XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7387 ctxt->URL, NULL);
7388 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007389 return (NULL);
7390 }
7391 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007392 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007393 xmlFreeDoc(doc);
7394 return (NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007395 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007396
7397 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007398 * Check the ref/defines links
7399 */
7400 /*
7401 * try to preprocess interleaves
7402 */
7403 if (ctxt->interleaves != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007404 xmlHashScan(ctxt->interleaves,
7405 (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007406 }
7407
7408 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007409 * if there was a parsing error return NULL
7410 */
7411 if (ctxt->nbErrors > 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007412 xmlRelaxNGFree(ret);
7413 ctxt->document = NULL;
7414 xmlFreeDoc(doc);
7415 return (NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007416 }
7417
7418 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007419 * try to compile (parts of) the schemas
7420 */
Daniel Veillardce192eb2003-04-16 15:58:05 +00007421 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7422 if (ret->topgrammar->start->type != XML_RELAXNG_START) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007423 xmlRelaxNGDefinePtr def;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007424
Daniel Veillard4c004142003-10-07 11:33:24 +00007425 def = xmlRelaxNGNewDefine(ctxt, NULL);
7426 if (def != NULL) {
7427 def->type = XML_RELAXNG_START;
7428 def->content = ret->topgrammar->start;
7429 ret->topgrammar->start = def;
7430 }
7431 }
7432 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007433 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007434
7435 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007436 * Transfer the pointer for cleanup at the schema level.
7437 */
7438 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007439 ctxt->document = NULL;
7440 ret->documents = ctxt->documents;
7441 ctxt->documents = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007442
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007443 ret->includes = ctxt->includes;
7444 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007445 ret->defNr = ctxt->defNr;
7446 ret->defTab = ctxt->defTab;
7447 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007448 if (ctxt->idref == 1)
Daniel Veillard4c004142003-10-07 11:33:24 +00007449 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007450
7451 return (ret);
7452}
Daniel Veillard4c004142003-10-07 11:33:24 +00007453
Daniel Veillard6eadf632003-01-23 18:29:16 +00007454/**
7455 * xmlRelaxNGSetParserErrors:
7456 * @ctxt: a Relax-NG validation context
7457 * @err: the error callback
7458 * @warn: the warning callback
7459 * @ctx: contextual data for the callbacks
7460 *
7461 * Set the callback functions used to handle errors for a validation context
7462 */
7463void
7464xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007465 xmlRelaxNGValidityErrorFunc err,
7466 xmlRelaxNGValidityWarningFunc warn, void *ctx)
7467{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007468 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007469 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007470 ctxt->error = err;
7471 ctxt->warning = warn;
7472 ctxt->userData = ctx;
7473}
Daniel Veillard409a8142003-07-18 15:16:57 +00007474
7475/**
7476 * xmlRelaxNGGetParserErrors:
7477 * @ctxt: a Relax-NG validation context
7478 * @err: the error callback result
7479 * @warn: the warning callback result
7480 * @ctx: contextual data for the callbacks result
7481 *
7482 * Get the callback information used to handle errors for a validation context
7483 *
7484 * Returns -1 in case of failure, 0 otherwise.
7485 */
7486int
7487xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007488 xmlRelaxNGValidityErrorFunc * err,
7489 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
7490{
Daniel Veillard409a8142003-07-18 15:16:57 +00007491 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007492 return (-1);
7493 if (err != NULL)
7494 *err = ctxt->error;
7495 if (warn != NULL)
7496 *warn = ctxt->warning;
7497 if (ctx != NULL)
7498 *ctx = ctxt->userData;
7499 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +00007500}
7501
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007502#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard4c004142003-10-07 11:33:24 +00007503
Daniel Veillard6eadf632003-01-23 18:29:16 +00007504/************************************************************************
7505 * *
7506 * Dump back a compiled form *
7507 * *
7508 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007509static void xmlRelaxNGDumpDefine(FILE * output,
7510 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007511
7512/**
7513 * xmlRelaxNGDumpDefines:
7514 * @output: the file output
7515 * @defines: a list of define structures
7516 *
7517 * Dump a RelaxNG structure back
7518 */
7519static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007520xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
7521{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007522 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007523 xmlRelaxNGDumpDefine(output, defines);
7524 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007525 }
7526}
7527
7528/**
7529 * xmlRelaxNGDumpDefine:
7530 * @output: the file output
7531 * @define: a define structure
7532 *
7533 * Dump a RelaxNG structure back
7534 */
7535static void
Daniel Veillard4c004142003-10-07 11:33:24 +00007536xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
7537{
Daniel Veillard6eadf632003-01-23 18:29:16 +00007538 if (define == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007539 return;
7540 switch (define->type) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007541 case XML_RELAXNG_EMPTY:
Daniel Veillard4c004142003-10-07 11:33:24 +00007542 fprintf(output, "<empty/>\n");
7543 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007544 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard4c004142003-10-07 11:33:24 +00007545 fprintf(output, "<notAllowed/>\n");
7546 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007547 case XML_RELAXNG_TEXT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007548 fprintf(output, "<text/>\n");
7549 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007550 case XML_RELAXNG_ELEMENT:
Daniel Veillard4c004142003-10-07 11:33:24 +00007551 fprintf(output, "<element>\n");
7552 if (define->name != NULL) {
7553 fprintf(output, "<name");
7554 if (define->ns != NULL)
7555 fprintf(output, " ns=\"%s\"", define->ns);
7556 fprintf(output, ">%s</name>\n", define->name);
7557 }
7558 xmlRelaxNGDumpDefines(output, define->attrs);
7559 xmlRelaxNGDumpDefines(output, define->content);
7560 fprintf(output, "</element>\n");
7561 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007562 case XML_RELAXNG_LIST:
Daniel Veillard4c004142003-10-07 11:33:24 +00007563 fprintf(output, "<list>\n");
7564 xmlRelaxNGDumpDefines(output, define->content);
7565 fprintf(output, "</list>\n");
7566 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007567 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007568 fprintf(output, "<oneOrMore>\n");
7569 xmlRelaxNGDumpDefines(output, define->content);
7570 fprintf(output, "</oneOrMore>\n");
7571 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007572 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007573 fprintf(output, "<zeroOrMore>\n");
7574 xmlRelaxNGDumpDefines(output, define->content);
7575 fprintf(output, "</zeroOrMore>\n");
7576 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007577 case XML_RELAXNG_CHOICE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007578 fprintf(output, "<choice>\n");
7579 xmlRelaxNGDumpDefines(output, define->content);
7580 fprintf(output, "</choice>\n");
7581 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007582 case XML_RELAXNG_GROUP:
Daniel Veillard4c004142003-10-07 11:33:24 +00007583 fprintf(output, "<group>\n");
7584 xmlRelaxNGDumpDefines(output, define->content);
7585 fprintf(output, "</group>\n");
7586 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007587 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007588 fprintf(output, "<interleave>\n");
7589 xmlRelaxNGDumpDefines(output, define->content);
7590 fprintf(output, "</interleave>\n");
7591 break;
7592 case XML_RELAXNG_OPTIONAL:
7593 fprintf(output, "<optional>\n");
7594 xmlRelaxNGDumpDefines(output, define->content);
7595 fprintf(output, "</optional>\n");
7596 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007597 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007598 fprintf(output, "<attribute>\n");
7599 xmlRelaxNGDumpDefines(output, define->content);
7600 fprintf(output, "</attribute>\n");
7601 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007602 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007603 fprintf(output, "<define");
7604 if (define->name != NULL)
7605 fprintf(output, " name=\"%s\"", define->name);
7606 fprintf(output, ">\n");
7607 xmlRelaxNGDumpDefines(output, define->content);
7608 fprintf(output, "</define>\n");
7609 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007610 case XML_RELAXNG_REF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007611 fprintf(output, "<ref");
7612 if (define->name != NULL)
7613 fprintf(output, " name=\"%s\"", define->name);
7614 fprintf(output, ">\n");
7615 xmlRelaxNGDumpDefines(output, define->content);
7616 fprintf(output, "</ref>\n");
7617 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007618 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00007619 fprintf(output, "<parentRef");
7620 if (define->name != NULL)
7621 fprintf(output, " name=\"%s\"", define->name);
7622 fprintf(output, ">\n");
7623 xmlRelaxNGDumpDefines(output, define->content);
7624 fprintf(output, "</parentRef>\n");
7625 break;
7626 case XML_RELAXNG_EXTERNALREF:
7627 fprintf(output, "<externalRef>");
7628 xmlRelaxNGDumpDefines(output, define->content);
7629 fprintf(output, "</externalRef>\n");
7630 break;
Daniel Veillarde431a272003-01-29 23:02:33 +00007631 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007632 case XML_RELAXNG_VALUE:
Daniel Veillard4c004142003-10-07 11:33:24 +00007633 TODO break;
7634 case XML_RELAXNG_START:
7635 case XML_RELAXNG_EXCEPT:
7636 case XML_RELAXNG_PARAM:
7637 TODO break;
7638 case XML_RELAXNG_NOOP:
7639 xmlRelaxNGDumpDefines(output, define->content);
7640 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007641 }
7642}
Daniel Veillard4c004142003-10-07 11:33:24 +00007643
Daniel Veillard6eadf632003-01-23 18:29:16 +00007644/**
7645 * xmlRelaxNGDumpGrammar:
7646 * @output: the file output
7647 * @grammar: a grammar structure
7648 * @top: is this a top grammar
7649 *
7650 * Dump a RelaxNG structure back
7651 */
7652static void
7653xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7654{
7655 if (grammar == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00007656 return;
7657
Daniel Veillard6eadf632003-01-23 18:29:16 +00007658 fprintf(output, "<grammar");
7659 if (top)
Daniel Veillard4c004142003-10-07 11:33:24 +00007660 fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7661 switch (grammar->combine) {
7662 case XML_RELAXNG_COMBINE_UNDEFINED:
7663 break;
7664 case XML_RELAXNG_COMBINE_CHOICE:
7665 fprintf(output, " combine=\"choice\"");
7666 break;
7667 case XML_RELAXNG_COMBINE_INTERLEAVE:
7668 fprintf(output, " combine=\"interleave\"");
7669 break;
7670 default:
7671 fprintf(output, " <!-- invalid combine value -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007672 }
7673 fprintf(output, ">\n");
7674 if (grammar->start == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007675 fprintf(output, " <!-- grammar had no start -->");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007676 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007677 fprintf(output, "<start>\n");
7678 xmlRelaxNGDumpDefine(output, grammar->start);
7679 fprintf(output, "</start>\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007680 }
7681 /* TODO ? Dump the defines ? */
7682 fprintf(output, "</grammar>\n");
7683}
7684
7685/**
7686 * xmlRelaxNGDump:
7687 * @output: the file output
7688 * @schema: a schema structure
7689 *
7690 * Dump a RelaxNG structure back
7691 */
7692void
7693xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7694{
Daniel Veillardce682bc2004-11-05 17:22:25 +00007695 if (output == NULL)
7696 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007697 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007698 fprintf(output, "RelaxNG empty or failed to compile\n");
7699 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007700 }
7701 fprintf(output, "RelaxNG: ");
7702 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007703 fprintf(output, "no document\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007704 } else if (schema->doc->URL != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007705 fprintf(output, "%s\n", schema->doc->URL);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007706 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007707 fprintf(output, "\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00007708 }
7709 if (schema->topgrammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007710 fprintf(output, "RelaxNG has no top grammar\n");
7711 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007712 }
7713 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7714}
7715
Daniel Veillardfebcca42003-02-16 15:44:18 +00007716/**
7717 * xmlRelaxNGDumpTree:
7718 * @output: the file output
7719 * @schema: a schema structure
7720 *
7721 * Dump the transformed RelaxNG tree.
7722 */
7723void
7724xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7725{
Daniel Veillardce682bc2004-11-05 17:22:25 +00007726 if (output == NULL)
7727 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007728 if (schema == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007729 fprintf(output, "RelaxNG empty or failed to compile\n");
7730 return;
Daniel Veillardfebcca42003-02-16 15:44:18 +00007731 }
7732 if (schema->doc == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007733 fprintf(output, "no document\n");
Daniel Veillardfebcca42003-02-16 15:44:18 +00007734 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00007735 xmlDocDump(output, schema->doc);
Daniel Veillardfebcca42003-02-16 15:44:18 +00007736 }
7737}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00007738#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardfebcca42003-02-16 15:44:18 +00007739
Daniel Veillard6eadf632003-01-23 18:29:16 +00007740/************************************************************************
7741 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007742 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007743 * *
7744 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007745static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7746 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007747
7748/**
7749 * xmlRelaxNGValidateCompiledCallback:
7750 * @exec: the regular expression instance
7751 * @token: the token which matched
7752 * @transdata: callback data, the define for the subelement if available
7753 @ @inputdata: callback data, the Relax NG validation context
7754 *
7755 * Handle the callback and if needed validate the element children.
7756 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007757static void
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007758xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00007759 const xmlChar * token,
7760 void *transdata, void *inputdata)
7761{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007762 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7763 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7764 int ret;
7765
7766#ifdef DEBUG_COMPILE
7767 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007768 "Compiled callback for: '%s'\n", token);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007769#endif
7770 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007771 fprintf(stderr, "callback on %s missing context\n", token);
7772 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7773 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7774 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007775 }
7776 if (define == NULL) {
7777 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007778 return;
7779 fprintf(stderr, "callback on %s missing define\n", token);
7780 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7781 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7782 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007783 }
7784 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007785 fprintf(stderr, "callback on %s missing info\n", token);
7786 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7787 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7788 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007789 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007790 fprintf(stderr, "callback on %s define is not element\n", token);
7791 if (ctxt->errNo == XML_RELAXNG_OK)
7792 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7793 return;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007794 }
7795 ret = xmlRelaxNGValidateDefinition(ctxt, define);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007796 if (ret != 0)
7797 ctxt->perr = ret;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007798}
7799
7800/**
7801 * xmlRelaxNGValidateCompiledContent:
7802 * @ctxt: the RelaxNG validation context
7803 * @regexp: the regular expression as compiled
7804 * @content: list of children to test against the regexp
7805 *
7806 * Validate the content model of an element or start using the regexp
7807 *
7808 * Returns 0 in case of success, -1 in case of error.
7809 */
7810static int
7811xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00007812 xmlRegexpPtr regexp, xmlNodePtr content)
7813{
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007814 xmlRegExecCtxtPtr exec;
7815 xmlNodePtr cur;
Daniel Veillard62163602003-04-17 09:36:38 +00007816 int ret = 0;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007817 int oldperr = ctxt->perr;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007818
7819 if ((ctxt == NULL) || (regexp == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00007820 return (-1);
7821 exec = xmlRegNewExecCtxt(regexp,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007822 xmlRelaxNGValidateCompiledCallback, ctxt);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007823 ctxt->perr = 0;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007824 cur = content;
7825 while (cur != NULL) {
7826 ctxt->state->seq = cur;
Daniel Veillard4c004142003-10-07 11:33:24 +00007827 switch (cur->type) {
7828 case XML_TEXT_NODE:
7829 case XML_CDATA_SECTION_NODE:
7830 if (xmlIsBlankNode(cur))
7831 break;
7832 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7833 if (ret < 0) {
7834 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
7835 cur->parent->name);
7836 }
7837 break;
7838 case XML_ELEMENT_NODE:
7839 if (cur->ns != NULL) {
7840 ret = xmlRegExecPushString2(exec, cur->name,
7841 cur->ns->href, ctxt);
7842 } else {
7843 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7844 }
7845 if (ret < 0) {
7846 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7847 }
7848 break;
7849 default:
7850 break;
7851 }
7852 if (ret < 0)
7853 break;
7854 /*
7855 * Switch to next element
7856 */
7857 cur = cur->next;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007858 }
7859 ret = xmlRegExecPushString(exec, NULL, NULL);
7860 if (ret == 1) {
7861 ret = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00007862 ctxt->state->seq = NULL;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007863 } else if (ret == 0) {
7864 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00007865 * TODO: get some of the names needed to exit the current state of exec
7866 */
7867 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7868 ret = -1;
7869 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7870 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007871 } else {
7872 ret = -1;
7873 }
7874 xmlRegFreeExecCtxt(exec);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +00007875 /*
7876 * There might be content model errors outside of the pure
7877 * regexp validation, e.g. for attribute values.
7878 */
7879 if ((ret == 0) && (ctxt->perr != 0)) {
7880 ret = ctxt->perr;
7881 }
7882 ctxt->perr = oldperr;
Daniel Veillard4c004142003-10-07 11:33:24 +00007883 return (ret);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007884}
7885
7886/************************************************************************
7887 * *
7888 * Progressive validation of when possible *
7889 * *
7890 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00007891static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7892 xmlRelaxNGDefinePtr defines);
7893static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
William M. Brack272693c2003-11-14 16:20:34 +00007894 int dolog);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00007895static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007896
7897/**
7898 * xmlRelaxNGElemPush:
7899 * @ctxt: the validation context
7900 * @exec: the regexp runtime for the new content model
7901 *
7902 * Push a new regexp for the current node content model on the stack
7903 *
7904 * Returns 0 in case of success and -1 in case of error.
7905 */
7906static int
Daniel Veillard4c004142003-10-07 11:33:24 +00007907xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
7908{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007909 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007910 ctxt->elemMax = 10;
7911 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7912 sizeof
7913 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007914 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007915 xmlRngVErrMemory(ctxt, "validating\n");
7916 return (-1);
7917 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007918 }
7919 if (ctxt->elemNr >= ctxt->elemMax) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007920 ctxt->elemMax *= 2;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007921 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
Daniel Veillard4c004142003-10-07 11:33:24 +00007922 ctxt->elemMax *
7923 sizeof
7924 (xmlRegExecCtxtPtr));
Daniel Veillardf4e55762003-04-15 23:32:22 +00007925 if (ctxt->elemTab == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007926 xmlRngVErrMemory(ctxt, "validating\n");
7927 return (-1);
7928 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00007929 }
7930 ctxt->elemTab[ctxt->elemNr++] = exec;
7931 ctxt->elem = exec;
Daniel Veillard4c004142003-10-07 11:33:24 +00007932 return (0);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007933}
7934
7935/**
7936 * xmlRelaxNGElemPop:
7937 * @ctxt: the validation context
7938 *
7939 * Pop the regexp of the current node content model from the stack
7940 *
7941 * Returns the exec or NULL if empty
7942 */
7943static xmlRegExecCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +00007944xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
7945{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007946 xmlRegExecCtxtPtr ret;
7947
Daniel Veillard4c004142003-10-07 11:33:24 +00007948 if (ctxt->elemNr <= 0)
7949 return (NULL);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007950 ctxt->elemNr--;
7951 ret = ctxt->elemTab[ctxt->elemNr];
7952 ctxt->elemTab[ctxt->elemNr] = NULL;
Daniel Veillard4c004142003-10-07 11:33:24 +00007953 if (ctxt->elemNr > 0)
Daniel Veillardf4e55762003-04-15 23:32:22 +00007954 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7955 else
Daniel Veillard4c004142003-10-07 11:33:24 +00007956 ctxt->elem = NULL;
7957 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007958}
7959
7960/**
7961 * xmlRelaxNGValidateProgressiveCallback:
7962 * @exec: the regular expression instance
7963 * @token: the token which matched
7964 * @transdata: callback data, the define for the subelement if available
7965 @ @inputdata: callback data, the Relax NG validation context
7966 *
7967 * Handle the callback and if needed validate the element children.
7968 * some of the in/out informations are passed via the context in @inputdata.
7969 */
Daniel Veillard4c004142003-10-07 11:33:24 +00007970static void
7971xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
7972 ATTRIBUTE_UNUSED,
7973 const xmlChar * token,
7974 void *transdata, void *inputdata)
7975{
Daniel Veillardf4e55762003-04-15 23:32:22 +00007976 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7977 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007978 xmlRelaxNGValidStatePtr state, oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007979 xmlNodePtr node = ctxt->pnode;
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00007980 int ret = 0, oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007981
7982#ifdef DEBUG_PROGRESSIVE
7983 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4c004142003-10-07 11:33:24 +00007984 "Progressive callback for: '%s'\n", token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007985#endif
7986 if (ctxt == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00007987 fprintf(stderr, "callback on %s missing context\n", token);
7988 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007989 }
7990 ctxt->pstate = 1;
7991 if (define == NULL) {
7992 if (token[0] == '#')
Daniel Veillard4c004142003-10-07 11:33:24 +00007993 return;
7994 fprintf(stderr, "callback on %s missing define\n", token);
7995 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7996 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7997 ctxt->pstate = -1;
7998 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007999 }
8000 if ((ctxt == NULL) || (define == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008001 fprintf(stderr, "callback on %s missing info\n", token);
8002 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8003 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8004 ctxt->pstate = -1;
8005 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008006 } else if (define->type != XML_RELAXNG_ELEMENT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008007 fprintf(stderr, "callback on %s define is not element\n", token);
8008 if (ctxt->errNo == XML_RELAXNG_OK)
8009 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8010 ctxt->pstate = -1;
8011 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008012 }
8013 if (node->type != XML_ELEMENT_NODE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008014 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8015 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8016 xmlRelaxNGDumpValidError(ctxt);
8017 ctxt->pstate = -1;
8018 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008019 }
8020 if (define->contModel == NULL) {
8021 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008022 * this node cannot be validated in a streamable fashion
8023 */
Daniel Veillardf4e55762003-04-15 23:32:22 +00008024#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008025 xmlGenericError(xmlGenericErrorContext,
8026 "Element '%s' validation is not streamable\n",
8027 token);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008028#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008029 ctxt->pstate = 0;
8030 ctxt->pdef = define;
8031 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008032 }
8033 exec = xmlRegNewExecCtxt(define->contModel,
Daniel Veillard4c004142003-10-07 11:33:24 +00008034 xmlRelaxNGValidateProgressiveCallback, ctxt);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008035 if (exec == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008036 ctxt->pstate = -1;
8037 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008038 }
8039 xmlRelaxNGElemPush(ctxt, exec);
8040
8041 /*
8042 * Validate the attributes part of the content.
8043 */
8044 state = xmlRelaxNGNewValidState(ctxt, node);
8045 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008046 ctxt->pstate = -1;
8047 return;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008048 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008049 oldstate = ctxt->state;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008050 ctxt->state = state;
8051 if (define->attrs != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008052 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8053 if (ret != 0) {
8054 ctxt->pstate = -1;
8055 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8056 }
Daniel Veillardf4e55762003-04-15 23:32:22 +00008057 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008058 if (ctxt->state != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008059 ctxt->state->seq = NULL;
8060 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
8061 if (ret != 0) {
8062 ctxt->pstate = -1;
8063 }
8064 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardce192eb2003-04-16 15:58:05 +00008065 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008066 int tmp = -1, i;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008067
8068 oldflags = ctxt->flags;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008069
Daniel Veillard4c004142003-10-07 11:33:24 +00008070 for (i = 0; i < ctxt->states->nbState; i++) {
8071 state = ctxt->states->tabState[i];
8072 ctxt->state = state;
8073 ctxt->state->seq = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00008074
Daniel Veillard4c004142003-10-07 11:33:24 +00008075 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
8076 tmp = 0;
8077 break;
8078 }
8079 }
8080 if (tmp != 0) {
8081 /*
8082 * validation error, log the message for the "best" one
8083 */
8084 ctxt->flags |= FLAGS_IGNORABLE;
8085 xmlRelaxNGLogBestError(ctxt);
8086 }
8087 for (i = 0; i < ctxt->states->nbState; i++) {
8088 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
8089 }
8090 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8091 ctxt->states = NULL;
8092 if ((ret == 0) && (tmp == -1))
8093 ctxt->pstate = -1;
8094 ctxt->flags = oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008095 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008096 if (ctxt->pstate == -1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008097 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8098 xmlRelaxNGDumpValidError(ctxt);
8099 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008100 }
8101 ctxt->state = oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008102}
8103
8104/**
8105 * xmlRelaxNGValidatePushElement:
8106 * @ctxt: the validation context
8107 * @doc: a document instance
8108 * @elem: an element instance
8109 *
8110 * Push a new element start on the RelaxNG validation stack.
8111 *
8112 * returns 1 if no validation problem was found or 0 if validating the
8113 * element requires a full node, and -1 in case of error.
8114 */
8115int
Daniel Veillard33300b42003-04-17 09:09:19 +00008116xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
8117 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00008118 xmlNodePtr elem)
8119{
8120 int ret = 1;
8121
8122 if ((ctxt == NULL) || (elem == NULL))
8123 return (-1);
8124
8125#ifdef DEBUG_PROGRESSIVE
8126 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
8127#endif
8128 if (ctxt->elem == 0) {
8129 xmlRelaxNGPtr schema;
8130 xmlRelaxNGGrammarPtr grammar;
8131 xmlRegExecCtxtPtr exec;
8132 xmlRelaxNGDefinePtr define;
8133
8134 schema = ctxt->schema;
8135 if (schema == NULL) {
8136 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8137 return (-1);
8138 }
8139 grammar = schema->topgrammar;
8140 if ((grammar == NULL) || (grammar->start == NULL)) {
8141 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8142 return (-1);
8143 }
8144 define = grammar->start;
8145 if (define->contModel == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008146 ctxt->pdef = define;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008147 return (0);
8148 }
8149 exec = xmlRegNewExecCtxt(define->contModel,
8150 xmlRelaxNGValidateProgressiveCallback,
8151 ctxt);
8152 if (exec == NULL) {
8153 return (-1);
8154 }
8155 xmlRelaxNGElemPush(ctxt, exec);
8156 }
8157 ctxt->pnode = elem;
8158 ctxt->pstate = 0;
8159 if (elem->ns != NULL) {
8160 ret =
8161 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8162 ctxt);
8163 } else {
8164 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8165 }
8166 if (ret < 0) {
8167 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8168 } else {
8169 if (ctxt->pstate == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008170 ret = 0;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008171 else if (ctxt->pstate < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008172 ret = -1;
8173 else
8174 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008175 }
8176#ifdef DEBUG_PROGRESSIVE
8177 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008178 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
8179 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008180#endif
8181 return (ret);
8182}
8183
8184/**
8185 * xmlRelaxNGValidatePushCData:
8186 * @ctxt: the RelaxNG validation context
8187 * @data: some character data read
8188 * @len: the lenght of the data
8189 *
8190 * check the CData parsed for validation in the current stack
8191 *
8192 * returns 1 if no validation problem was found or -1 otherwise
8193 */
8194int
8195xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00008196 const xmlChar * data, int len ATTRIBUTE_UNUSED)
Daniel Veillardf4e55762003-04-15 23:32:22 +00008197{
8198 int ret = 1;
8199
8200 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8201 return (-1);
8202
8203#ifdef DEBUG_PROGRESSIVE
8204 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
8205#endif
8206
8207 while (*data != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008208 if (!IS_BLANK_CH(*data))
Daniel Veillardf4e55762003-04-15 23:32:22 +00008209 break;
8210 data++;
8211 }
8212 if (*data == 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008213 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008214
8215 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8216 if (ret < 0) {
Daniel Veillard33300b42003-04-17 09:09:19 +00008217 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008218#ifdef DEBUG_PROGRESSIVE
Daniel Veillard4c004142003-10-07 11:33:24 +00008219 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
Daniel Veillardf4e55762003-04-15 23:32:22 +00008220#endif
8221
Daniel Veillard4c004142003-10-07 11:33:24 +00008222 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008223 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008224 return (1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008225}
8226
8227/**
8228 * xmlRelaxNGValidatePopElement:
8229 * @ctxt: the RelaxNG validation context
8230 * @doc: a document instance
8231 * @elem: an element instance
8232 *
8233 * Pop the element end from the RelaxNG validation stack.
8234 *
8235 * returns 1 if no validation problem was found or 0 otherwise
8236 */
8237int
8238xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8239 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008240 xmlNodePtr elem)
8241{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008242 int ret;
8243 xmlRegExecCtxtPtr exec;
8244
Daniel Veillard4c004142003-10-07 11:33:24 +00008245 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
8246 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008247#ifdef DEBUG_PROGRESSIVE
8248 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8249#endif
8250 /*
8251 * verify that we reached a terminal state of the content model.
8252 */
8253 exec = xmlRelaxNGElemPop(ctxt);
8254 ret = xmlRegExecPushString(exec, NULL, NULL);
8255 if (ret == 0) {
8256 /*
Daniel Veillard4c004142003-10-07 11:33:24 +00008257 * TODO: get some of the names needed to exit the current state of exec
8258 */
8259 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8260 ret = -1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008261 } else if (ret < 0) {
8262 ret = -1;
8263 } else {
8264 ret = 1;
8265 }
8266 xmlRegFreeExecCtxt(exec);
8267#ifdef DEBUG_PROGRESSIVE
8268 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008269 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8270 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008271#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008272 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008273}
8274
8275/**
8276 * xmlRelaxNGValidateFullElement:
8277 * @ctxt: the validation context
8278 * @doc: a document instance
8279 * @elem: an element instance
8280 *
8281 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8282 * 0 and the content of the node has been expanded.
8283 *
8284 * returns 1 if no validation problem was found or -1 in case of error.
8285 */
8286int
Daniel Veillard33300b42003-04-17 09:09:19 +00008287xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8288 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008289 xmlNodePtr elem)
8290{
Daniel Veillardf4e55762003-04-15 23:32:22 +00008291 int ret;
8292 xmlRelaxNGValidStatePtr state;
8293
Daniel Veillard4c004142003-10-07 11:33:24 +00008294 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
8295 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008296#ifdef DEBUG_PROGRESSIVE
8297 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8298#endif
8299 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8300 if (state == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008301 return (-1);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008302 }
8303 state->seq = elem;
8304 ctxt->state = state;
8305 ctxt->errNo = XML_RELAXNG_OK;
8306 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
Daniel Veillard4c004142003-10-07 11:33:24 +00008307 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
8308 ret = -1;
8309 else
8310 ret = 1;
Daniel Veillardf4e55762003-04-15 23:32:22 +00008311 xmlRelaxNGFreeValidState(ctxt, state);
8312 ctxt->state = NULL;
8313#ifdef DEBUG_PROGRESSIVE
8314 if (ret < 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008315 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8316 elem->name);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008317#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008318 return (ret);
Daniel Veillardf4e55762003-04-15 23:32:22 +00008319}
8320
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008321/************************************************************************
8322 * *
8323 * Generic interpreted validation implementation *
8324 * *
8325 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +00008326static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8327 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008328
8329/**
8330 * xmlRelaxNGSkipIgnored:
8331 * @ctxt: a schema validation context
8332 * @node: the top node.
8333 *
8334 * Skip ignorable nodes in that context
8335 *
8336 * Returns the new sibling or NULL in case of error.
8337 */
8338static xmlNodePtr
8339xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
Daniel Veillard4c004142003-10-07 11:33:24 +00008340 xmlNodePtr node)
8341{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008342 /*
8343 * TODO complete and handle entities
8344 */
8345 while ((node != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00008346 ((node->type == XML_COMMENT_NODE) ||
8347 (node->type == XML_PI_NODE) ||
William M. Brack7217c862004-03-15 02:43:56 +00008348 (node->type == XML_XINCLUDE_START) ||
8349 (node->type == XML_XINCLUDE_END) ||
Daniel Veillard4c004142003-10-07 11:33:24 +00008350 (((node->type == XML_TEXT_NODE) ||
8351 (node->type == XML_CDATA_SECTION_NODE)) &&
8352 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8353 (IS_BLANK_NODE(node)))))) {
8354 node = node->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008355 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008356 return (node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008357}
8358
8359/**
Daniel Veillardedc91922003-01-26 00:52:04 +00008360 * xmlRelaxNGNormalize:
8361 * @ctxt: a schema validation context
8362 * @str: the string to normalize
8363 *
8364 * Implements the normalizeWhiteSpace( s ) function from
8365 * section 6.2.9 of the spec
8366 *
8367 * Returns the new string or NULL in case of error.
8368 */
8369static xmlChar *
Daniel Veillard4c004142003-10-07 11:33:24 +00008370xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
8371{
Daniel Veillardedc91922003-01-26 00:52:04 +00008372 xmlChar *ret, *p;
8373 const xmlChar *tmp;
8374 int len;
Daniel Veillard4c004142003-10-07 11:33:24 +00008375
Daniel Veillardedc91922003-01-26 00:52:04 +00008376 if (str == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008377 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008378 tmp = str;
Daniel Veillard4c004142003-10-07 11:33:24 +00008379 while (*tmp != 0)
8380 tmp++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008381 len = tmp - str;
8382
Daniel Veillard3c908dc2003-04-19 00:07:51 +00008383 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
Daniel Veillardedc91922003-01-26 00:52:04 +00008384 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008385 xmlRngVErrMemory(ctxt, "validating\n");
8386 return (NULL);
Daniel Veillardedc91922003-01-26 00:52:04 +00008387 }
8388 p = ret;
William M. Brack76e95df2003-10-18 16:20:14 +00008389 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008390 str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008391 while (*str != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008392 if (IS_BLANK_CH(*str)) {
8393 while (IS_BLANK_CH(*str))
Daniel Veillard4c004142003-10-07 11:33:24 +00008394 str++;
8395 if (*str == 0)
8396 break;
8397 *p++ = ' ';
8398 } else
8399 *p++ = *str++;
Daniel Veillardedc91922003-01-26 00:52:04 +00008400 }
8401 *p = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00008402 return (ret);
Daniel Veillardedc91922003-01-26 00:52:04 +00008403}
8404
8405/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008406 * xmlRelaxNGValidateDatatype:
8407 * @ctxt: a Relax-NG validation context
8408 * @value: the string value
8409 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008410 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008411 *
8412 * Validate the given value against the dataype
8413 *
8414 * Returns 0 if the validation succeeded or an error code.
8415 */
8416static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008417xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
8418 const xmlChar * value,
8419 xmlRelaxNGDefinePtr define, xmlNodePtr node)
8420{
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008421 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008422 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008423 void *result = NULL;
8424 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008425
8426 if ((define == NULL) || (define->data == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008427 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008428 }
8429 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008430 if (lib->check != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008431 if ((define->attrs != NULL) &&
8432 (define->attrs->type == XML_RELAXNG_PARAM)) {
8433 ret =
8434 lib->check(lib->data, define->name, value, &result, node);
8435 } else {
8436 ret = lib->check(lib->data, define->name, value, NULL, node);
8437 }
8438 } else
8439 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008440 if (ret < 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008441 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8442 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8443 lib->freef(lib->data, result);
8444 return (-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008445 } else if (ret == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008446 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008447 } else if (ret == 2) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008448 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008449 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008450 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8451 ret = -1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008452 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008453 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008454 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008455 if (lib->facet != NULL) {
8456 tmp = lib->facet(lib->data, define->name, cur->name,
8457 cur->value, value, result);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008458 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008459 ret = -1;
8460 }
8461 cur = cur->next;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008462 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008463 if ((ret == 0) && (define->content != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008464 const xmlChar *oldvalue, *oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008465
Daniel Veillard4c004142003-10-07 11:33:24 +00008466 oldvalue = ctxt->state->value;
8467 oldendvalue = ctxt->state->endvalue;
8468 ctxt->state->value = (xmlChar *) value;
8469 ctxt->state->endvalue = NULL;
8470 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8471 ctxt->state->value = (xmlChar *) oldvalue;
8472 ctxt->state->endvalue = (xmlChar *) oldendvalue;
Daniel Veillard416589a2003-02-17 17:25:42 +00008473 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008474 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00008475 lib->freef(lib->data, result);
8476 return (ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008477}
8478
8479/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008480 * xmlRelaxNGNextValue:
8481 * @ctxt: a Relax-NG validation context
8482 *
8483 * Skip to the next value when validating within a list
8484 *
8485 * Returns 0 if the operation succeeded or an error code.
8486 */
8487static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008488xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
8489{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008490 xmlChar *cur;
8491
8492 cur = ctxt->state->value;
8493 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008494 ctxt->state->value = NULL;
8495 ctxt->state->endvalue = NULL;
8496 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008497 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008498 while (*cur != 0)
8499 cur++;
8500 while ((cur != ctxt->state->endvalue) && (*cur == 0))
8501 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008502 if (cur == ctxt->state->endvalue)
Daniel Veillard4c004142003-10-07 11:33:24 +00008503 ctxt->state->value = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008504 else
Daniel Veillard4c004142003-10-07 11:33:24 +00008505 ctxt->state->value = cur;
8506 return (0);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008507}
8508
8509/**
8510 * xmlRelaxNGValidateValueList:
8511 * @ctxt: a Relax-NG validation context
8512 * @defines: the list of definitions to verify
8513 *
8514 * Validate the given set of definitions for the current value
8515 *
8516 * Returns 0 if the validation succeeded or an error code.
8517 */
8518static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008519xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8520 xmlRelaxNGDefinePtr defines)
8521{
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008522 int ret = 0;
8523
8524 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008525 ret = xmlRelaxNGValidateValue(ctxt, defines);
8526 if (ret != 0)
8527 break;
8528 defines = defines->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008529 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008530 return (ret);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008531}
8532
8533/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008534 * xmlRelaxNGValidateValue:
8535 * @ctxt: a Relax-NG validation context
8536 * @define: the definition to verify
8537 *
8538 * Validate the given definition for the current value
8539 *
8540 * Returns 0 if the validation succeeded or an error code.
8541 */
8542static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008543xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8544 xmlRelaxNGDefinePtr define)
8545{
Daniel Veillardedc91922003-01-26 00:52:04 +00008546 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008547 xmlChar *value;
8548
8549 value = ctxt->state->value;
8550 switch (define->type) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008551 case XML_RELAXNG_EMPTY:{
8552 if ((value != NULL) && (value[0] != 0)) {
8553 int idx = 0;
Daniel Veillardd4310742003-02-18 21:12:46 +00008554
William M. Brack76e95df2003-10-18 16:20:14 +00008555 while (IS_BLANK_CH(value[idx]))
Daniel Veillard4c004142003-10-07 11:33:24 +00008556 idx++;
8557 if (value[idx] != 0)
8558 ret = -1;
8559 }
8560 break;
8561 }
8562 case XML_RELAXNG_TEXT:
8563 break;
8564 case XML_RELAXNG_VALUE:{
8565 if (!xmlStrEqual(value, define->value)) {
8566 if (define->name != NULL) {
8567 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillardedc91922003-01-26 00:52:04 +00008568
Daniel Veillard4c004142003-10-07 11:33:24 +00008569 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8570 if ((lib != NULL) && (lib->comp != NULL)) {
8571 ret = lib->comp(lib->data, define->name,
8572 define->value, define->node,
8573 (void *) define->attrs,
8574 value, ctxt->state->node);
8575 } else
8576 ret = -1;
8577 if (ret < 0) {
8578 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
8579 define->name);
8580 return (-1);
8581 } else if (ret == 1) {
8582 ret = 0;
8583 } else {
8584 ret = -1;
8585 }
8586 } else {
8587 xmlChar *nval, *nvalue;
Daniel Veillardedc91922003-01-26 00:52:04 +00008588
Daniel Veillard4c004142003-10-07 11:33:24 +00008589 /*
8590 * TODO: trivial optimizations are possible by
8591 * computing at compile-time
8592 */
8593 nval = xmlRelaxNGNormalize(ctxt, define->value);
8594 nvalue = xmlRelaxNGNormalize(ctxt, value);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008595
Daniel Veillard4c004142003-10-07 11:33:24 +00008596 if ((nval == NULL) || (nvalue == NULL) ||
8597 (!xmlStrEqual(nval, nvalue)))
8598 ret = -1;
8599 if (nval != NULL)
8600 xmlFree(nval);
8601 if (nvalue != NULL)
8602 xmlFree(nvalue);
8603 }
8604 }
8605 if (ret == 0)
8606 xmlRelaxNGNextValue(ctxt);
8607 break;
8608 }
8609 case XML_RELAXNG_DATATYPE:{
8610 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8611 ctxt->state->seq);
8612 if (ret == 0)
8613 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008614
Daniel Veillard4c004142003-10-07 11:33:24 +00008615 break;
8616 }
8617 case XML_RELAXNG_CHOICE:{
8618 xmlRelaxNGDefinePtr list = define->content;
8619 xmlChar *oldvalue;
8620
8621 oldflags = ctxt->flags;
8622 ctxt->flags |= FLAGS_IGNORABLE;
8623
8624 oldvalue = ctxt->state->value;
8625 while (list != NULL) {
8626 ret = xmlRelaxNGValidateValue(ctxt, list);
8627 if (ret == 0) {
8628 break;
8629 }
8630 ctxt->state->value = oldvalue;
8631 list = list->next;
8632 }
8633 ctxt->flags = oldflags;
8634 if (ret != 0) {
8635 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8636 xmlRelaxNGDumpValidError(ctxt);
8637 } else {
8638 if (ctxt->errNr > 0)
8639 xmlRelaxNGPopErrors(ctxt, 0);
8640 }
8641 if (ret == 0)
8642 xmlRelaxNGNextValue(ctxt);
8643 break;
8644 }
8645 case XML_RELAXNG_LIST:{
8646 xmlRelaxNGDefinePtr list = define->content;
8647 xmlChar *oldvalue, *oldend, *val, *cur;
8648
Daniel Veillard416589a2003-02-17 17:25:42 +00008649#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008650 int nb_values = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008651#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008652
Daniel Veillard4c004142003-10-07 11:33:24 +00008653 oldvalue = ctxt->state->value;
8654 oldend = ctxt->state->endvalue;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008655
Daniel Veillard4c004142003-10-07 11:33:24 +00008656 val = xmlStrdup(oldvalue);
8657 if (val == NULL) {
8658 val = xmlStrdup(BAD_CAST "");
8659 }
8660 if (val == NULL) {
8661 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8662 return (-1);
8663 }
8664 cur = val;
8665 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008666 if (IS_BLANK_CH(*cur)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008667 *cur = 0;
8668 cur++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008669#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008670 nb_values++;
Daniel Veillard416589a2003-02-17 17:25:42 +00008671#endif
William M. Brack76e95df2003-10-18 16:20:14 +00008672 while (IS_BLANK_CH(*cur))
Daniel Veillard4c004142003-10-07 11:33:24 +00008673 *cur++ = 0;
8674 } else
8675 cur++;
8676 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008677#ifdef DEBUG_LIST
Daniel Veillard4c004142003-10-07 11:33:24 +00008678 xmlGenericError(xmlGenericErrorContext,
8679 "list value: '%s' found %d items\n",
8680 oldvalue, nb_values);
8681 nb_values = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008682#endif
Daniel Veillard4c004142003-10-07 11:33:24 +00008683 ctxt->state->endvalue = cur;
8684 cur = val;
8685 while ((*cur == 0) && (cur != ctxt->state->endvalue))
8686 cur++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008687
Daniel Veillard4c004142003-10-07 11:33:24 +00008688 ctxt->state->value = cur;
8689
8690 while (list != NULL) {
8691 if (ctxt->state->value == ctxt->state->endvalue)
8692 ctxt->state->value = NULL;
8693 ret = xmlRelaxNGValidateValue(ctxt, list);
8694 if (ret != 0) {
8695#ifdef DEBUG_LIST
8696 xmlGenericError(xmlGenericErrorContext,
8697 "Failed to validate value: '%s' with %d rule\n",
8698 ctxt->state->value, nb_values);
8699#endif
8700 break;
8701 }
8702#ifdef DEBUG_LIST
8703 nb_values++;
8704#endif
8705 list = list->next;
8706 }
8707
8708 if ((ret == 0) && (ctxt->state->value != NULL) &&
8709 (ctxt->state->value != ctxt->state->endvalue)) {
8710 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
8711 ctxt->state->value);
8712 ret = -1;
8713 }
8714 xmlFree(val);
8715 ctxt->state->value = oldvalue;
8716 ctxt->state->endvalue = oldend;
8717 break;
8718 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008719 case XML_RELAXNG_ONEORMORE:
Daniel Veillard4c004142003-10-07 11:33:24 +00008720 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8721 if (ret != 0) {
8722 break;
8723 }
8724 /* no break on purpose */
8725 case XML_RELAXNG_ZEROORMORE:{
8726 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008727
Daniel Veillard4c004142003-10-07 11:33:24 +00008728 oldflags = ctxt->flags;
8729 ctxt->flags |= FLAGS_IGNORABLE;
8730 cur = ctxt->state->value;
8731 temp = NULL;
8732 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8733 (temp != cur)) {
8734 temp = cur;
8735 ret =
8736 xmlRelaxNGValidateValueList(ctxt, define->content);
8737 if (ret != 0) {
8738 ctxt->state->value = temp;
8739 ret = 0;
8740 break;
8741 }
8742 cur = ctxt->state->value;
8743 }
8744 ctxt->flags = oldflags;
8745 if (ret != 0) {
8746 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8747 xmlRelaxNGDumpValidError(ctxt);
8748 } else {
8749 if (ctxt->errNr > 0)
8750 xmlRelaxNGPopErrors(ctxt, 0);
8751 }
8752 break;
8753 }
8754 case XML_RELAXNG_EXCEPT:{
8755 xmlRelaxNGDefinePtr list;
Daniel Veillard416589a2003-02-17 17:25:42 +00008756
Daniel Veillard4c004142003-10-07 11:33:24 +00008757 list = define->content;
8758 while (list != NULL) {
8759 ret = xmlRelaxNGValidateValue(ctxt, list);
8760 if (ret == 0) {
8761 ret = -1;
8762 break;
8763 } else
8764 ret = 0;
8765 list = list->next;
8766 }
8767 break;
8768 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008769 case XML_RELAXNG_DEF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008770 case XML_RELAXNG_GROUP:{
8771 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008772
Daniel Veillard4c004142003-10-07 11:33:24 +00008773 list = define->content;
8774 while (list != NULL) {
8775 ret = xmlRelaxNGValidateValue(ctxt, list);
8776 if (ret != 0) {
8777 ret = -1;
8778 break;
8779 } else
8780 ret = 0;
8781 list = list->next;
8782 }
8783 break;
8784 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008785 case XML_RELAXNG_REF:
8786 case XML_RELAXNG_PARENTREF:
Daniel Veillard4c004142003-10-07 11:33:24 +00008787 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8788 break;
8789 default:
8790 TODO ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008791 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008792 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008793}
8794
8795/**
8796 * xmlRelaxNGValidateValueContent:
8797 * @ctxt: a Relax-NG validation context
8798 * @defines: the list of definitions to verify
8799 *
8800 * Validate the given definitions for the current value
8801 *
8802 * Returns 0 if the validation succeeded or an error code.
8803 */
8804static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008805xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8806 xmlRelaxNGDefinePtr defines)
8807{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008808 int ret = 0;
8809
8810 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008811 ret = xmlRelaxNGValidateValue(ctxt, defines);
8812 if (ret != 0)
8813 break;
8814 defines = defines->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008815 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008816 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008817}
8818
8819/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008820 * xmlRelaxNGAttributeMatch:
8821 * @ctxt: a Relax-NG validation context
8822 * @define: the definition to check
8823 * @prop: the attribute
8824 *
8825 * Check if the attribute matches the definition nameClass
8826 *
8827 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8828 */
8829static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008830xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8831 xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
8832{
Daniel Veillardfd573f12003-03-16 17:52:32 +00008833 int ret;
8834
8835 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008836 if (!xmlStrEqual(define->name, prop->name))
8837 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008838 }
8839 if (define->ns != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008840 if (define->ns[0] == 0) {
8841 if (prop->ns != NULL)
8842 return (0);
8843 } else {
8844 if ((prop->ns == NULL) ||
8845 (!xmlStrEqual(define->ns, prop->ns->href)))
8846 return (0);
8847 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008848 }
8849 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00008850 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008851 define = define->nameClass;
8852 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008853 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008854
Daniel Veillard4c004142003-10-07 11:33:24 +00008855 list = define->content;
8856 while (list != NULL) {
8857 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8858 if (ret == 1)
8859 return (0);
8860 if (ret < 0)
8861 return (ret);
8862 list = list->next;
8863 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008864 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008865 TODO}
8866 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008867}
8868
8869/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008870 * xmlRelaxNGValidateAttribute:
8871 * @ctxt: a Relax-NG validation context
8872 * @define: the definition to verify
8873 *
8874 * Validate the given attribute definition for that node
8875 *
8876 * Returns 0 if the validation succeeded or an error code.
8877 */
8878static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008879xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8880 xmlRelaxNGDefinePtr define)
8881{
Daniel Veillard6eadf632003-01-23 18:29:16 +00008882 int ret = 0, i;
8883 xmlChar *value, *oldvalue;
8884 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008885 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008886
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008887 if (ctxt->state->nbAttrLeft <= 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00008888 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008889 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008890 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8891 tmp = ctxt->state->attrs[i];
8892 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8893 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8894 (tmp->ns == NULL)) ||
8895 ((tmp->ns != NULL) &&
8896 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8897 prop = tmp;
8898 break;
8899 }
8900 }
8901 }
8902 if (prop != NULL) {
8903 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8904 oldvalue = ctxt->state->value;
8905 oldseq = ctxt->state->seq;
8906 ctxt->state->seq = (xmlNodePtr) prop;
8907 ctxt->state->value = value;
8908 ctxt->state->endvalue = NULL;
8909 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8910 if (ctxt->state->value != NULL)
8911 value = ctxt->state->value;
8912 if (value != NULL)
8913 xmlFree(value);
8914 ctxt->state->value = oldvalue;
8915 ctxt->state->seq = oldseq;
8916 if (ret == 0) {
8917 /*
8918 * flag the attribute as processed
8919 */
8920 ctxt->state->attrs[i] = NULL;
8921 ctxt->state->nbAttrLeft--;
8922 }
8923 } else {
8924 ret = -1;
8925 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008926#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008927 xmlGenericError(xmlGenericErrorContext,
8928 "xmlRelaxNGValidateAttribute(%s): %d\n",
8929 define->name, ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008930#endif
8931 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00008932 for (i = 0; i < ctxt->state->nbAttrs; i++) {
8933 tmp = ctxt->state->attrs[i];
8934 if ((tmp != NULL) &&
8935 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
8936 prop = tmp;
8937 break;
8938 }
8939 }
8940 if (prop != NULL) {
8941 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8942 oldvalue = ctxt->state->value;
8943 oldseq = ctxt->state->seq;
8944 ctxt->state->seq = (xmlNodePtr) prop;
8945 ctxt->state->value = value;
8946 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8947 if (ctxt->state->value != NULL)
8948 value = ctxt->state->value;
8949 if (value != NULL)
8950 xmlFree(value);
8951 ctxt->state->value = oldvalue;
8952 ctxt->state->seq = oldseq;
8953 if (ret == 0) {
8954 /*
8955 * flag the attribute as processed
8956 */
8957 ctxt->state->attrs[i] = NULL;
8958 ctxt->state->nbAttrLeft--;
8959 }
8960 } else {
8961 ret = -1;
8962 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008963#ifdef DEBUG
Daniel Veillard4c004142003-10-07 11:33:24 +00008964 if (define->ns != NULL) {
8965 xmlGenericError(xmlGenericErrorContext,
8966 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8967 define->ns, ret);
8968 } else {
8969 xmlGenericError(xmlGenericErrorContext,
8970 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8971 ret);
8972 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008973#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008974 }
Daniel Veillard4c004142003-10-07 11:33:24 +00008975
8976 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008977}
8978
8979/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008980 * xmlRelaxNGValidateAttributeList:
8981 * @ctxt: a Relax-NG validation context
8982 * @define: the list of definition to verify
8983 *
8984 * Validate the given node against the list of attribute definitions
8985 *
8986 * Returns 0 if the validation succeeded or an error code.
8987 */
8988static int
Daniel Veillard4c004142003-10-07 11:33:24 +00008989xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8990 xmlRelaxNGDefinePtr defines)
8991{
Daniel Veillardce192eb2003-04-16 15:58:05 +00008992 int ret = 0, res;
8993 int needmore = 0;
8994 xmlRelaxNGDefinePtr cur;
8995
8996 cur = defines;
8997 while (cur != NULL) {
8998 if (cur->type == XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00008999 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
9000 ret = -1;
9001 } else
9002 needmore = 1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009003 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009004 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00009005 if (!needmore)
Daniel Veillard4c004142003-10-07 11:33:24 +00009006 return (ret);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009007 cur = defines;
9008 while (cur != NULL) {
9009 if (cur->type != XML_RELAXNG_ATTRIBUTE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009010 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9011 res = xmlRelaxNGValidateDefinition(ctxt, cur);
9012 if (res < 0)
9013 ret = -1;
9014 } else {
9015 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9016 return (-1);
9017 }
9018 if (res == -1) /* continues on -2 */
9019 break;
9020 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00009021 cur = cur->next;
9022 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009023
9024 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009025}
9026
9027/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009028 * xmlRelaxNGNodeMatchesList:
9029 * @node: the node
9030 * @list: a NULL terminated array of definitions
9031 *
9032 * Check if a node can be matched by one of the definitions
9033 *
9034 * Returns 1 if matches 0 otherwise
9035 */
9036static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009037xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
9038{
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009039 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009040 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009041
9042 if ((node == NULL) || (list == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +00009043 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009044
9045 cur = list[i++];
9046 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009047 if ((node->type == XML_ELEMENT_NODE) &&
9048 (cur->type == XML_RELAXNG_ELEMENT)) {
9049 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
9050 if (tmp == 1)
9051 return (1);
9052 } else if (((node->type == XML_TEXT_NODE) ||
9053 (node->type == XML_CDATA_SECTION_NODE)) &&
9054 (cur->type == XML_RELAXNG_TEXT)) {
9055 return (1);
9056 }
9057 cur = list[i++];
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009058 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009059 return (0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00009060}
9061
9062/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009063 * xmlRelaxNGValidateInterleave:
9064 * @ctxt: a Relax-NG validation context
9065 * @define: the definition to verify
9066 *
9067 * Validate an interleave definition for a node.
9068 *
9069 * Returns 0 if the validation succeeded or an error code.
9070 */
9071static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009072xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
9073 xmlRelaxNGDefinePtr define)
9074{
William M. Brack779af002003-08-01 15:55:39 +00009075 int ret = 0, i, nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009076 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009077 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009078
9079 xmlRelaxNGValidStatePtr oldstate;
9080 xmlRelaxNGPartitionPtr partitions;
9081 xmlRelaxNGInterleaveGroupPtr group = NULL;
9082 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
9083 xmlNodePtr *list = NULL, *lasts = NULL;
9084
9085 if (define->data != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009086 partitions = (xmlRelaxNGPartitionPtr) define->data;
9087 nbgroups = partitions->nbgroups;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009088 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009089 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
9090 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009091 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009092 /*
9093 * Optimizations for MIXED
9094 */
9095 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00009096 if (define->dflags & IS_MIXED) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009097 ctxt->flags |= FLAGS_MIXED_CONTENT;
9098 if (nbgroups == 2) {
9099 /*
9100 * this is a pure <mixed> case
9101 */
9102 if (ctxt->state != NULL)
9103 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9104 ctxt->state->seq);
9105 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
9106 ret = xmlRelaxNGValidateDefinition(ctxt,
9107 partitions->groups[1]->
9108 rule);
9109 else
9110 ret = xmlRelaxNGValidateDefinition(ctxt,
9111 partitions->groups[0]->
9112 rule);
9113 if (ret == 0) {
9114 if (ctxt->state != NULL)
9115 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9116 ctxt->state->
9117 seq);
9118 }
9119 ctxt->flags = oldflags;
9120 return (ret);
9121 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009122 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009123
9124 /*
9125 * Build arrays to store the first and last node of the chain
9126 * pertaining to each group
9127 */
9128 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9129 if (list == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009130 xmlRngVErrMemory(ctxt, "validating\n");
9131 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009132 }
9133 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
9134 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9135 if (lasts == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009136 xmlRngVErrMemory(ctxt, "validating\n");
9137 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009138 }
9139 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
9140
9141 /*
9142 * Walk the sequence of children finding the right group and
9143 * sorting them in sequences.
9144 */
9145 cur = ctxt->state->seq;
9146 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9147 start = cur;
9148 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009149 ctxt->state->seq = cur;
9150 if ((partitions->triage != NULL) &&
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009151 (partitions->flags & IS_DETERMINIST)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009152 void *tmp = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009153
Daniel Veillard4c004142003-10-07 11:33:24 +00009154 if ((cur->type == XML_TEXT_NODE) ||
9155 (cur->type == XML_CDATA_SECTION_NODE)) {
9156 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
9157 NULL);
9158 } else if (cur->type == XML_ELEMENT_NODE) {
9159 if (cur->ns != NULL) {
9160 tmp = xmlHashLookup2(partitions->triage, cur->name,
9161 cur->ns->href);
9162 if (tmp == NULL)
9163 tmp = xmlHashLookup2(partitions->triage,
9164 BAD_CAST "#any",
9165 cur->ns->href);
9166 } else
9167 tmp =
9168 xmlHashLookup2(partitions->triage, cur->name,
9169 NULL);
9170 if (tmp == NULL)
9171 tmp =
9172 xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9173 NULL);
9174 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009175
Daniel Veillard4c004142003-10-07 11:33:24 +00009176 if (tmp == NULL) {
9177 i = nbgroups;
9178 } else {
9179 i = ((long) tmp) - 1;
9180 if (partitions->flags & IS_NEEDCHECK) {
9181 group = partitions->groups[i];
9182 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9183 i = nbgroups;
9184 }
9185 }
9186 } else {
9187 for (i = 0; i < nbgroups; i++) {
9188 group = partitions->groups[i];
9189 if (group == NULL)
9190 continue;
9191 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9192 break;
9193 }
9194 }
9195 /*
9196 * We break as soon as an element not matched is found
9197 */
9198 if (i >= nbgroups) {
9199 break;
9200 }
9201 if (lasts[i] != NULL) {
9202 lasts[i]->next = cur;
9203 lasts[i] = cur;
9204 } else {
9205 list[i] = cur;
9206 lasts[i] = cur;
9207 }
9208 if (cur->next != NULL)
9209 lastchg = cur->next;
9210 else
9211 lastchg = cur;
9212 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009213 }
9214 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009215 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9216 ret = -1;
9217 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009218 }
9219 lastelem = cur;
9220 oldstate = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009221 for (i = 0; i < nbgroups; i++) {
9222 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9223 group = partitions->groups[i];
9224 if (lasts[i] != NULL) {
9225 last = lasts[i]->next;
9226 lasts[i]->next = NULL;
9227 }
9228 ctxt->state->seq = list[i];
9229 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9230 if (ret != 0)
9231 break;
9232 if (ctxt->state != NULL) {
9233 cur = ctxt->state->seq;
9234 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9235 xmlRelaxNGFreeValidState(ctxt, oldstate);
9236 oldstate = ctxt->state;
9237 ctxt->state = NULL;
9238 if (cur != NULL) {
9239 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9240 ret = -1;
9241 ctxt->state = oldstate;
9242 goto done;
9243 }
9244 } else if (ctxt->states != NULL) {
9245 int j;
9246 int found = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009247
Daniel Veillard4c004142003-10-07 11:33:24 +00009248 for (j = 0; j < ctxt->states->nbState; j++) {
9249 cur = ctxt->states->tabState[j]->seq;
9250 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9251 if (cur == NULL) {
9252 found = 1;
9253 break;
9254 }
9255 }
9256 if (ctxt->states->nbState > 0) {
9257 xmlRelaxNGFreeValidState(ctxt, oldstate);
9258 oldstate =
9259 ctxt->states->tabState[ctxt->states->nbState - 1];
9260 }
9261 for (j = 0; j < ctxt->states->nbState - 1; j++) {
9262 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
9263 }
9264 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9265 ctxt->states = NULL;
9266 if (found == 0) {
9267 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9268 ret = -1;
9269 ctxt->state = oldstate;
9270 goto done;
9271 }
9272 } else {
9273 ret = -1;
9274 break;
9275 }
9276 if (lasts[i] != NULL) {
9277 lasts[i]->next = last;
9278 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009279 }
9280 if (ctxt->state != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009281 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009282 ctxt->state = oldstate;
9283 ctxt->state->seq = lastelem;
9284 if (ret != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009285 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9286 ret = -1;
9287 goto done;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009288 }
9289
Daniel Veillard4c004142003-10-07 11:33:24 +00009290 done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009291 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009292 /*
9293 * builds the next links chain from the prev one
9294 */
9295 cur = lastchg;
9296 while (cur != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009297 if ((cur == start) || (cur->prev == NULL))
9298 break;
9299 cur->prev->next = cur;
9300 cur = cur->prev;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009301 }
9302 if (ret == 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009303 if (ctxt->errNr > errNr)
9304 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009305 }
9306
9307 xmlFree(list);
9308 xmlFree(lasts);
Daniel Veillard4c004142003-10-07 11:33:24 +00009309 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009310}
9311
9312/**
9313 * xmlRelaxNGValidateDefinitionList:
9314 * @ctxt: a Relax-NG validation context
9315 * @define: the list of definition to verify
9316 *
9317 * Validate the given node content against the (list) of definitions
9318 *
9319 * Returns 0 if the validation succeeded or an error code.
9320 */
9321static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009322xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9323 xmlRelaxNGDefinePtr defines)
9324{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009325 int ret = 0, res;
9326
9327
Daniel Veillard952379b2003-03-17 15:37:12 +00009328 if (defines == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009329 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
9330 BAD_CAST "NULL definition list");
9331 return (-1);
Daniel Veillard952379b2003-03-17 15:37:12 +00009332 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009333 while (defines != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009334 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9335 res = xmlRelaxNGValidateDefinition(ctxt, defines);
9336 if (res < 0)
9337 ret = -1;
9338 } else {
9339 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9340 return (-1);
9341 }
9342 if (res == -1) /* continues on -2 */
9343 break;
9344 defines = defines->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009345 }
9346
Daniel Veillard4c004142003-10-07 11:33:24 +00009347 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009348}
9349
9350/**
9351 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00009352 * @ctxt: a Relax-NG validation context
9353 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00009354 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00009355 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009356 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00009357 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009358 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00009359 */
9360static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009361xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9362 xmlRelaxNGDefinePtr define, xmlNodePtr elem)
9363{
Daniel Veillard580ced82003-03-21 21:22:48 +00009364 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00009365
Daniel Veillardfd573f12003-03-16 17:52:32 +00009366 if (define->name != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009367 if (!xmlStrEqual(elem->name, define->name)) {
9368 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9369 return (0);
9370 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009371 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009372 if ((define->ns != NULL) && (define->ns[0] != 0)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009373 if (elem->ns == NULL) {
9374 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
9375 return (0);
9376 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9377 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9378 elem->name, define->ns);
9379 return (0);
9380 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009381 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
Daniel Veillard4c004142003-10-07 11:33:24 +00009382 (define->name == NULL)) {
9383 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
9384 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009385 } else if ((elem->ns != NULL) && (define->name != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009386 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
9387 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009388 }
9389
9390 if (define->nameClass == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +00009391 return (1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009392
9393 define = define->nameClass;
9394 if (define->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009395 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009396
Daniel Veillard4c004142003-10-07 11:33:24 +00009397 if (ctxt != NULL) {
9398 oldflags = ctxt->flags;
9399 ctxt->flags |= FLAGS_IGNORABLE;
9400 }
9401
9402 list = define->content;
9403 while (list != NULL) {
9404 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9405 if (ret == 1) {
9406 if (ctxt != NULL)
9407 ctxt->flags = oldflags;
9408 return (0);
9409 }
9410 if (ret < 0) {
9411 if (ctxt != NULL)
9412 ctxt->flags = oldflags;
9413 return (ret);
9414 }
9415 list = list->next;
9416 }
9417 ret = 1;
9418 if (ctxt != NULL) {
9419 ctxt->flags = oldflags;
9420 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009421 } else if (define->type == XML_RELAXNG_CHOICE) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009422 xmlRelaxNGDefinePtr list;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009423
Daniel Veillard4c004142003-10-07 11:33:24 +00009424 if (ctxt != NULL) {
9425 oldflags = ctxt->flags;
9426 ctxt->flags |= FLAGS_IGNORABLE;
9427 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009428
Daniel Veillard4c004142003-10-07 11:33:24 +00009429 list = define->nameClass;
9430 while (list != NULL) {
9431 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9432 if (ret == 1) {
9433 if (ctxt != NULL)
9434 ctxt->flags = oldflags;
9435 return (1);
9436 }
9437 if (ret < 0) {
9438 if (ctxt != NULL)
9439 ctxt->flags = oldflags;
9440 return (ret);
9441 }
9442 list = list->next;
9443 }
9444 if (ctxt != NULL) {
9445 if (ret != 0) {
9446 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9447 xmlRelaxNGDumpValidError(ctxt);
9448 } else {
9449 if (ctxt->errNr > 0)
9450 xmlRelaxNGPopErrors(ctxt, 0);
9451 }
9452 }
9453 ret = 0;
9454 if (ctxt != NULL) {
9455 ctxt->flags = oldflags;
9456 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009457 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +00009458 TODO ret = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009459 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009460 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009461}
9462
9463/**
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009464 * xmlRelaxNGBestState:
9465 * @ctxt: a Relax-NG validation context
9466 *
9467 * Find the "best" state in the ctxt->states list of states to report
9468 * errors about. I.e. a state with no element left in the child list
9469 * or the one with the less attributes left.
9470 * This is called only if a falidation error was detected
9471 *
9472 * Returns the index of the "best" state or -1 in case of error
9473 */
9474static int
Daniel Veillard4c004142003-10-07 11:33:24 +00009475xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
9476{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009477 xmlRelaxNGValidStatePtr state;
9478 int i, tmp;
9479 int best = -1;
9480 int value = 1000000;
9481
9482 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9483 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009484 return (-1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009485
Daniel Veillard4c004142003-10-07 11:33:24 +00009486 for (i = 0; i < ctxt->states->nbState; i++) {
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009487 state = ctxt->states->tabState[i];
Daniel Veillard4c004142003-10-07 11:33:24 +00009488 if (state == NULL)
9489 continue;
9490 if (state->seq != NULL) {
9491 if ((best == -1) || (value > 100000)) {
9492 value = 100000;
9493 best = i;
9494 }
9495 } else {
9496 tmp = state->nbAttrLeft;
9497 if ((best == -1) || (value > tmp)) {
9498 value = tmp;
9499 best = i;
9500 }
9501 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009502 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009503 return (best);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009504}
9505
9506/**
9507 * xmlRelaxNGLogBestError:
9508 * @ctxt: a Relax-NG validation context
9509 *
9510 * Find the "best" state in the ctxt->states list of states to report
9511 * errors about and log it.
9512 */
9513static void
Daniel Veillard4c004142003-10-07 11:33:24 +00009514xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
9515{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009516 int best;
9517
9518 if ((ctxt == NULL) || (ctxt->states == NULL) ||
9519 (ctxt->states->nbState <= 0))
Daniel Veillard4c004142003-10-07 11:33:24 +00009520 return;
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009521
9522 best = xmlRelaxNGBestState(ctxt);
9523 if ((best >= 0) && (best < ctxt->states->nbState)) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009524 ctxt->state = ctxt->states->tabState[best];
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009525
Daniel Veillard4c004142003-10-07 11:33:24 +00009526 xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009527 }
9528}
9529
9530/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009531 * xmlRelaxNGValidateElementEnd:
9532 * @ctxt: a Relax-NG validation context
William M. Brack272693c2003-11-14 16:20:34 +00009533 * @dolog: indicate that error logging should be done
Daniel Veillardfd573f12003-03-16 17:52:32 +00009534 *
9535 * Validate the end of the element, implements check that
9536 * there is nothing left not consumed in the element content
9537 * or in the attribute list.
9538 *
9539 * Returns 0 if the validation succeeded or an error code.
9540 */
9541static int
William M. Brack272693c2003-11-14 16:20:34 +00009542xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
Daniel Veillard4c004142003-10-07 11:33:24 +00009543{
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009544 int i;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009545 xmlRelaxNGValidStatePtr state;
9546
9547 state = ctxt->state;
9548 if (state->seq != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009549 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9550 if (state->seq != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009551 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009552 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9553 state->node->name, state->seq->name);
9554 }
9555 return (-1);
9556 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009557 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009558 for (i = 0; i < state->nbAttrs; i++) {
9559 if (state->attrs[i] != NULL) {
William M. Brack272693c2003-11-14 16:20:34 +00009560 if (dolog) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009561 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9562 state->attrs[i]->name, state->node->name);
9563 }
9564 return (-1 - i);
9565 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009566 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009567 return (0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009568}
9569
9570/**
9571 * xmlRelaxNGValidateState:
9572 * @ctxt: a Relax-NG validation context
9573 * @define: the definition to verify
9574 *
9575 * Validate the current state against the definition
9576 *
9577 * Returns 0 if the validation succeeded or an error code.
9578 */
9579static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009580xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9581 xmlRelaxNGDefinePtr define)
9582{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009583 xmlNodePtr node;
9584 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009585 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009586
9587 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009588 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9589 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009590 }
9591
9592 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009593 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009594 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009595 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009596 }
9597#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009598 for (i = 0; i < ctxt->depth; i++)
9599 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009600 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009601 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009602 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009603 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009604 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009605 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009606 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009607 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009608#endif
9609 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009610 switch (define->type) {
9611 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009612 node = xmlRelaxNGSkipIgnored(ctxt, node);
9613 ret = 0;
9614 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009615 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009616 ret = -1;
9617 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009618 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009619 while ((node != NULL) &&
9620 ((node->type == XML_TEXT_NODE) ||
9621 (node->type == XML_COMMENT_NODE) ||
9622 (node->type == XML_PI_NODE) ||
9623 (node->type == XML_CDATA_SECTION_NODE)))
9624 node = node->next;
9625 ctxt->state->seq = node;
9626 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009627 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009628 errNr = ctxt->errNr;
9629 node = xmlRelaxNGSkipIgnored(ctxt, node);
9630 if (node == NULL) {
9631 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9632 ret = -1;
9633 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9634 xmlRelaxNGDumpValidError(ctxt);
9635 break;
9636 }
9637 if (node->type != XML_ELEMENT_NODE) {
9638 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9639 ret = -1;
9640 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9641 xmlRelaxNGDumpValidError(ctxt);
9642 break;
9643 }
9644 /*
9645 * This node was already validated successfully against
9646 * this definition.
9647 */
Daniel Veillard807daf82004-02-22 22:13:27 +00009648 if (node->psvi == define) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009649 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9650 if (ctxt->errNr > errNr)
9651 xmlRelaxNGPopErrors(ctxt, errNr);
9652 if (ctxt->errNr != 0) {
9653 while ((ctxt->err != NULL) &&
9654 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9655 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9656 ||
9657 ((ctxt->err->err ==
9658 XML_RELAXNG_ERR_ELEMEXTRANS)
9659 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9660 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9661 || (ctxt->err->err ==
9662 XML_RELAXNG_ERR_NOTELEM)))
9663 xmlRelaxNGValidErrorPop(ctxt);
9664 }
9665 break;
9666 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009667
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009668 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9669 if (ret <= 0) {
9670 ret = -1;
9671 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9672 xmlRelaxNGDumpValidError(ctxt);
9673 break;
9674 }
9675 ret = 0;
9676 if (ctxt->errNr != 0) {
9677 if (ctxt->errNr > errNr)
9678 xmlRelaxNGPopErrors(ctxt, errNr);
9679 while ((ctxt->err != NULL) &&
9680 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9681 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9682 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9683 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9684 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9685 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9686 xmlRelaxNGValidErrorPop(ctxt);
9687 }
9688 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009689
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009690 oldflags = ctxt->flags;
9691 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9692 ctxt->flags -= FLAGS_MIXED_CONTENT;
9693 }
9694 state = xmlRelaxNGNewValidState(ctxt, node);
9695 if (state == NULL) {
9696 ret = -1;
9697 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9698 xmlRelaxNGDumpValidError(ctxt);
9699 break;
9700 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009701
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009702 oldstate = ctxt->state;
9703 ctxt->state = state;
9704 if (define->attrs != NULL) {
9705 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9706 if (tmp != 0) {
9707 ret = -1;
9708 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9709 }
9710 }
9711 if (define->contModel != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +00009712 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9713 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9714 xmlNodePtr nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009715
Daniel Veillard4c004142003-10-07 11:33:24 +00009716 nstate = xmlRelaxNGNewValidState(ctxt, node);
9717 ctxt->state = nstate;
9718 ctxt->states = NULL;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009719
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009720 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9721 define->contModel,
9722 ctxt->state->seq);
Daniel Veillard4c004142003-10-07 11:33:24 +00009723 nseq = ctxt->state->seq;
9724 ctxt->state = tmpstate;
9725 ctxt->states = tmpstates;
9726 xmlRelaxNGFreeValidState(ctxt, nstate);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009727
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009728#ifdef DEBUG_COMPILE
Daniel Veillard4c004142003-10-07 11:33:24 +00009729 xmlGenericError(xmlGenericErrorContext,
9730 "Validating content of '%s' : %d\n",
9731 define->name, tmp);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009732#endif
Daniel Veillardce192eb2003-04-16 15:58:05 +00009733 if (tmp != 0)
Daniel Veillard4c004142003-10-07 11:33:24 +00009734 ret = -1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009735
9736 if (ctxt->states != NULL) {
9737 tmp = -1;
9738
Daniel Veillardce192eb2003-04-16 15:58:05 +00009739 for (i = 0; i < ctxt->states->nbState; i++) {
9740 state = ctxt->states->tabState[i];
9741 ctxt->state = state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009742 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009743
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009744 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00009745 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009746 break;
9747 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009748 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009749 if (tmp != 0) {
9750 /*
9751 * validation error, log the message for the "best" one
9752 */
9753 ctxt->flags |= FLAGS_IGNORABLE;
9754 xmlRelaxNGLogBestError(ctxt);
9755 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009756 for (i = 0; i < ctxt->states->nbState; i++) {
9757 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009758 ctxt->states->
9759 tabState[i]);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009760 }
9761 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9762 ctxt->flags = oldflags;
9763 ctxt->states = NULL;
9764 if ((ret == 0) && (tmp == -1))
9765 ret = -1;
9766 } else {
9767 state = ctxt->state;
Daniel Veillard4c004142003-10-07 11:33:24 +00009768 ctxt->state->seq = nseq;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009769 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009770 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009771 xmlRelaxNGFreeValidState(ctxt, state);
9772 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009773 } else {
9774 if (define->content != NULL) {
9775 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009776 define->
9777 content);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009778 if (tmp != 0) {
9779 ret = -1;
9780 if (ctxt->state == NULL) {
9781 ctxt->state = oldstate;
9782 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9783 node->name);
9784 ctxt->state = NULL;
9785 } else {
9786 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9787 node->name);
9788 }
9789
9790 }
9791 }
9792 if (ctxt->states != NULL) {
9793 tmp = -1;
9794
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009795 for (i = 0; i < ctxt->states->nbState; i++) {
9796 state = ctxt->states->tabState[i];
9797 ctxt->state = state;
9798
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009799 if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009800 tmp = 0;
Daniel Veillard4c004142003-10-07 11:33:24 +00009801 break;
9802 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009803 }
Daniel Veillard4c004142003-10-07 11:33:24 +00009804 if (tmp != 0) {
9805 /*
9806 * validation error, log the message for the "best" one
9807 */
9808 ctxt->flags |= FLAGS_IGNORABLE;
9809 xmlRelaxNGLogBestError(ctxt);
9810 }
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009811 for (i = 0; i < ctxt->states->nbState; i++) {
9812 xmlRelaxNGFreeValidState(ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +00009813 ctxt->states->
9814 tabState[i]);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009815 }
9816 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9817 ctxt->flags = oldflags;
9818 ctxt->states = NULL;
9819 if ((ret == 0) && (tmp == -1))
9820 ret = -1;
9821 } else {
9822 state = ctxt->state;
9823 if (ret == 0)
Daniel Veillard1ac24d32003-08-27 14:15:15 +00009824 ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009825 xmlRelaxNGFreeValidState(ctxt, state);
9826 }
9827 }
9828 if (ret == 0) {
Daniel Veillard807daf82004-02-22 22:13:27 +00009829 node->psvi = define;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009830 }
9831 ctxt->flags = oldflags;
9832 ctxt->state = oldstate;
9833 if (oldstate != NULL)
9834 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9835 if (ret != 0) {
9836 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9837 xmlRelaxNGDumpValidError(ctxt);
9838 ret = 0;
9839 } else {
9840 ret = -2;
9841 }
9842 } else {
9843 if (ctxt->errNr > errNr)
9844 xmlRelaxNGPopErrors(ctxt, errNr);
9845 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009846
9847#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009848 xmlGenericError(xmlGenericErrorContext,
9849 "xmlRelaxNGValidateDefinition(): validated %s : %d",
9850 node->name, ret);
9851 if (oldstate == NULL)
9852 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9853 else if (oldstate->seq == NULL)
9854 xmlGenericError(xmlGenericErrorContext, ": done\n");
9855 else if (oldstate->seq->type == XML_ELEMENT_NODE)
9856 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9857 oldstate->seq->name);
9858 else
9859 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9860 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009861#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009862 break;
9863 case XML_RELAXNG_OPTIONAL:{
9864 errNr = ctxt->errNr;
9865 oldflags = ctxt->flags;
9866 ctxt->flags |= FLAGS_IGNORABLE;
9867 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9868 ret =
9869 xmlRelaxNGValidateDefinitionList(ctxt,
9870 define->content);
9871 if (ret != 0) {
9872 if (ctxt->state != NULL)
9873 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9874 ctxt->state = oldstate;
9875 ctxt->flags = oldflags;
9876 ret = 0;
9877 if (ctxt->errNr > errNr)
9878 xmlRelaxNGPopErrors(ctxt, errNr);
9879 break;
9880 }
9881 if (ctxt->states != NULL) {
9882 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9883 } else {
9884 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9885 if (ctxt->states == NULL) {
9886 xmlRelaxNGFreeValidState(ctxt, oldstate);
9887 ctxt->flags = oldflags;
9888 ret = -1;
9889 if (ctxt->errNr > errNr)
9890 xmlRelaxNGPopErrors(ctxt, errNr);
9891 break;
9892 }
9893 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9894 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9895 ctxt->state = NULL;
9896 }
9897 ctxt->flags = oldflags;
9898 ret = 0;
9899 if (ctxt->errNr > errNr)
9900 xmlRelaxNGPopErrors(ctxt, errNr);
9901 break;
9902 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009903 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009904 errNr = ctxt->errNr;
9905 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9906 if (ret != 0) {
9907 break;
9908 }
9909 if (ctxt->errNr > errNr)
9910 xmlRelaxNGPopErrors(ctxt, errNr);
9911 /* no break on purpose */
9912 case XML_RELAXNG_ZEROORMORE:{
9913 int progress;
9914 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9915 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009916
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009917 errNr = ctxt->errNr;
9918 res = xmlRelaxNGNewStates(ctxt, 1);
9919 if (res == NULL) {
9920 ret = -1;
9921 break;
9922 }
9923 /*
9924 * All the input states are also exit states
9925 */
9926 if (ctxt->state != NULL) {
9927 xmlRelaxNGAddStates(ctxt, res,
9928 xmlRelaxNGCopyValidState(ctxt,
9929 ctxt->
9930 state));
9931 } else {
9932 for (j = 0; j < ctxt->states->nbState; j++) {
9933 xmlRelaxNGAddStates(ctxt, res,
9934 xmlRelaxNGCopyValidState(ctxt,
9935 ctxt->
9936 states->
9937 tabState
9938 [j]));
9939 }
9940 }
9941 oldflags = ctxt->flags;
9942 ctxt->flags |= FLAGS_IGNORABLE;
9943 do {
9944 progress = 0;
9945 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009946
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009947 if (ctxt->states != NULL) {
9948 states = ctxt->states;
9949 for (i = 0; i < states->nbState; i++) {
9950 ctxt->state = states->tabState[i];
9951 ctxt->states = NULL;
9952 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9953 define->
9954 content);
9955 if (ret == 0) {
9956 if (ctxt->state != NULL) {
9957 tmp = xmlRelaxNGAddStates(ctxt, res,
9958 ctxt->state);
9959 ctxt->state = NULL;
9960 if (tmp == 1)
9961 progress = 1;
9962 } else if (ctxt->states != NULL) {
9963 for (j = 0; j < ctxt->states->nbState;
9964 j++) {
9965 tmp =
9966 xmlRelaxNGAddStates(ctxt, res,
9967 ctxt->
9968 states->
9969 tabState
9970 [j]);
9971 if (tmp == 1)
9972 progress = 1;
9973 }
9974 xmlRelaxNGFreeStates(ctxt,
9975 ctxt->states);
9976 ctxt->states = NULL;
9977 }
9978 } else {
9979 if (ctxt->state != NULL) {
9980 xmlRelaxNGFreeValidState(ctxt,
9981 ctxt->state);
9982 ctxt->state = NULL;
9983 }
9984 }
9985 }
9986 } else {
9987 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9988 define->
9989 content);
9990 if (ret != 0) {
9991 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9992 ctxt->state = NULL;
9993 } else {
9994 base = res->nbState;
9995 if (ctxt->state != NULL) {
9996 tmp = xmlRelaxNGAddStates(ctxt, res,
9997 ctxt->state);
9998 ctxt->state = NULL;
9999 if (tmp == 1)
10000 progress = 1;
10001 } else if (ctxt->states != NULL) {
10002 for (j = 0; j < ctxt->states->nbState; j++) {
10003 tmp = xmlRelaxNGAddStates(ctxt, res,
10004 ctxt->
10005 states->
10006 tabState[j]);
10007 if (tmp == 1)
10008 progress = 1;
10009 }
10010 if (states == NULL) {
10011 states = ctxt->states;
10012 } else {
10013 xmlRelaxNGFreeStates(ctxt,
10014 ctxt->states);
10015 }
10016 ctxt->states = NULL;
10017 }
10018 }
10019 }
10020 if (progress) {
10021 /*
10022 * Collect all the new nodes added at that step
10023 * and make them the new node set
10024 */
10025 if (res->nbState - base == 1) {
10026 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
10027 res->
10028 tabState
10029 [base]);
10030 } else {
10031 if (states == NULL) {
10032 xmlRelaxNGNewStates(ctxt,
10033 res->nbState - base);
10034 }
10035 states->nbState = 0;
10036 for (i = base; i < res->nbState; i++)
10037 xmlRelaxNGAddStates(ctxt, states,
10038 xmlRelaxNGCopyValidState
10039 (ctxt,
10040 res->tabState[i]));
10041 ctxt->states = states;
10042 }
10043 }
10044 } while (progress == 1);
10045 if (states != NULL) {
10046 xmlRelaxNGFreeStates(ctxt, states);
10047 }
10048 ctxt->states = res;
10049 ctxt->flags = oldflags;
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010050#if 0
10051 /*
Daniel Veillard4c004142003-10-07 11:33:24 +000010052 * errors may have to be propagated back...
10053 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010054 if (ctxt->errNr > errNr)
10055 xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardc1ffa0a2003-08-26 13:56:48 +000010056#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010057 ret = 0;
10058 break;
10059 }
10060 case XML_RELAXNG_CHOICE:{
10061 xmlRelaxNGDefinePtr list = NULL;
10062 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010063
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010064 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010065
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010066 errNr = ctxt->errNr;
Daniel Veillard9186a1f2005-01-15 12:38:10 +000010067 if ((define->dflags & IS_TRIABLE) && (define->data != NULL) &&
10068 (node != NULL)) {
10069 /*
10070 * node == NULL can't be optimized since IS_TRIABLE
10071 * doesn't account for choice which may lead to
10072 * only attributes.
10073 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010074 xmlHashTablePtr triage =
10075 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +000010076
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010077 /*
10078 * Something we can optimize cleanly there is only one
10079 * possble branch out !
10080 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010081 if ((node->type == XML_TEXT_NODE) ||
10082 (node->type == XML_CDATA_SECTION_NODE)) {
10083 list =
10084 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10085 } else if (node->type == XML_ELEMENT_NODE) {
10086 if (node->ns != NULL) {
10087 list = xmlHashLookup2(triage, node->name,
10088 node->ns->href);
10089 if (list == NULL)
10090 list =
10091 xmlHashLookup2(triage, BAD_CAST "#any",
10092 node->ns->href);
10093 } else
10094 list =
10095 xmlHashLookup2(triage, node->name, NULL);
10096 if (list == NULL)
10097 list =
10098 xmlHashLookup2(triage, BAD_CAST "#any",
10099 NULL);
10100 }
10101 if (list == NULL) {
10102 ret = -1;
William M. Brack2f076062004-03-21 11:21:14 +000010103 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010104 break;
10105 }
10106 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10107 if (ret == 0) {
10108 }
10109 break;
10110 }
Daniel Veillarde063f482003-03-21 16:53:17 +000010111
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010112 list = define->content;
10113 oldflags = ctxt->flags;
10114 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010115
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010116 while (list != NULL) {
10117 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10118 ret = xmlRelaxNGValidateDefinition(ctxt, list);
10119 if (ret == 0) {
10120 if (states == NULL) {
10121 states = xmlRelaxNGNewStates(ctxt, 1);
10122 }
10123 if (ctxt->state != NULL) {
10124 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10125 } else if (ctxt->states != NULL) {
10126 for (i = 0; i < ctxt->states->nbState; i++) {
10127 xmlRelaxNGAddStates(ctxt, states,
10128 ctxt->states->
10129 tabState[i]);
10130 }
10131 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10132 ctxt->states = NULL;
10133 }
10134 } else {
10135 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10136 }
10137 ctxt->state = oldstate;
10138 list = list->next;
10139 }
10140 if (states != NULL) {
10141 xmlRelaxNGFreeValidState(ctxt, oldstate);
10142 ctxt->states = states;
10143 ctxt->state = NULL;
10144 ret = 0;
10145 } else {
10146 ctxt->states = NULL;
10147 }
10148 ctxt->flags = oldflags;
10149 if (ret != 0) {
10150 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10151 xmlRelaxNGDumpValidError(ctxt);
10152 }
10153 } else {
10154 if (ctxt->errNr > errNr)
10155 xmlRelaxNGPopErrors(ctxt, errNr);
10156 }
10157 break;
10158 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010159 case XML_RELAXNG_DEF:
10160 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010161 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10162 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010163 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010164 ret = xmlRelaxNGValidateInterleave(ctxt, define);
10165 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010166 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010167 ret = xmlRelaxNGValidateAttribute(ctxt, define);
10168 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +000010169 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010170 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +000010171 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010172 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +000010173 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010174 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10175 break;
10176 case XML_RELAXNG_DATATYPE:{
10177 xmlNodePtr child;
10178 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010179
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010180 child = node;
10181 while (child != NULL) {
10182 if (child->type == XML_ELEMENT_NODE) {
10183 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10184 node->parent->name);
10185 ret = -1;
10186 break;
10187 } else if ((child->type == XML_TEXT_NODE) ||
10188 (child->type == XML_CDATA_SECTION_NODE)) {
10189 content = xmlStrcat(content, child->content);
10190 }
10191 /* TODO: handle entities ... */
10192 child = child->next;
10193 }
10194 if (ret == -1) {
10195 if (content != NULL)
10196 xmlFree(content);
10197 break;
10198 }
10199 if (content == NULL) {
10200 content = xmlStrdup(BAD_CAST "");
10201 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010202 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010203 ret = -1;
10204 break;
10205 }
10206 }
10207 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10208 ctxt->state->seq);
10209 if (ret == -1) {
10210 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10211 } else if (ret == 0) {
10212 ctxt->state->seq = NULL;
10213 }
10214 if (content != NULL)
10215 xmlFree(content);
10216 break;
10217 }
10218 case XML_RELAXNG_VALUE:{
10219 xmlChar *content = NULL;
10220 xmlChar *oldvalue;
10221 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010222
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010223 child = node;
10224 while (child != NULL) {
10225 if (child->type == XML_ELEMENT_NODE) {
10226 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10227 node->parent->name);
10228 ret = -1;
10229 break;
10230 } else if ((child->type == XML_TEXT_NODE) ||
10231 (child->type == XML_CDATA_SECTION_NODE)) {
10232 content = xmlStrcat(content, child->content);
10233 }
10234 /* TODO: handle entities ... */
10235 child = child->next;
10236 }
10237 if (ret == -1) {
10238 if (content != NULL)
10239 xmlFree(content);
10240 break;
10241 }
10242 if (content == NULL) {
10243 content = xmlStrdup(BAD_CAST "");
10244 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010245 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010246 ret = -1;
10247 break;
10248 }
10249 }
10250 oldvalue = ctxt->state->value;
10251 ctxt->state->value = content;
10252 ret = xmlRelaxNGValidateValue(ctxt, define);
10253 ctxt->state->value = oldvalue;
10254 if (ret == -1) {
10255 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10256 } else if (ret == 0) {
10257 ctxt->state->seq = NULL;
10258 }
10259 if (content != NULL)
10260 xmlFree(content);
10261 break;
10262 }
10263 case XML_RELAXNG_LIST:{
10264 xmlChar *content;
10265 xmlNodePtr child;
10266 xmlChar *oldvalue, *oldendvalue;
10267 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010268
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010269 /*
10270 * Make sure it's only text nodes
10271 */
10272
10273 content = NULL;
10274 child = node;
10275 while (child != NULL) {
10276 if (child->type == XML_ELEMENT_NODE) {
10277 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10278 node->parent->name);
10279 ret = -1;
10280 break;
10281 } else if ((child->type == XML_TEXT_NODE) ||
10282 (child->type == XML_CDATA_SECTION_NODE)) {
10283 content = xmlStrcat(content, child->content);
10284 }
10285 /* TODO: handle entities ... */
10286 child = child->next;
10287 }
10288 if (ret == -1) {
10289 if (content != NULL)
10290 xmlFree(content);
10291 break;
10292 }
10293 if (content == NULL) {
10294 content = xmlStrdup(BAD_CAST "");
10295 if (content == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010296 xmlRngVErrMemory(ctxt, "validating\n");
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010297 ret = -1;
10298 break;
10299 }
10300 }
10301 len = xmlStrlen(content);
10302 oldvalue = ctxt->state->value;
10303 oldendvalue = ctxt->state->endvalue;
10304 ctxt->state->value = content;
10305 ctxt->state->endvalue = content + len;
10306 ret = xmlRelaxNGValidateValue(ctxt, define);
10307 ctxt->state->value = oldvalue;
10308 ctxt->state->endvalue = oldendvalue;
10309 if (ret == -1) {
10310 VALID_ERR(XML_RELAXNG_ERR_LIST);
10311 } else if ((ret == 0) && (node != NULL)) {
10312 ctxt->state->seq = node->next;
10313 }
10314 if (content != NULL)
10315 xmlFree(content);
10316 break;
10317 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010318 case XML_RELAXNG_EXCEPT:
10319 case XML_RELAXNG_PARAM:
10320 TODO ret = -1;
10321 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010322 }
10323 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010324#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010325 for (i = 0; i < ctxt->depth; i++)
10326 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010327 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010328 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +000010329 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010330 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010331 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010332 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +000010333 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010334 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010335#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000010336 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010337}
10338
10339/**
Daniel Veillardfd573f12003-03-16 17:52:32 +000010340 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010341 * @ctxt: a Relax-NG validation context
10342 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010343 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010344 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010345 *
Daniel Veillardfd573f12003-03-16 17:52:32 +000010346 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010347 */
10348static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010349xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10350 xmlRelaxNGDefinePtr define)
10351{
Daniel Veillardfd573f12003-03-16 17:52:32 +000010352 xmlRelaxNGStatesPtr states, res;
10353 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010354
Daniel Veillardfd573f12003-03-16 17:52:32 +000010355 /*
10356 * We should NOT have both ctxt->state and ctxt->states
10357 */
10358 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010359 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10360 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010361 }
10362
10363 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010364 if (ctxt->states != NULL) {
10365 ctxt->state = ctxt->states->tabState[0];
10366 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10367 ctxt->states = NULL;
10368 }
10369 ret = xmlRelaxNGValidateState(ctxt, define);
10370 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10371 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10372 ctxt->state = NULL;
10373 }
10374 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10375 ctxt->state = ctxt->states->tabState[0];
10376 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10377 ctxt->states = NULL;
10378 }
10379 return (ret);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010380 }
10381
10382 states = ctxt->states;
10383 ctxt->states = NULL;
10384 res = NULL;
10385 j = 0;
10386 oldflags = ctxt->flags;
10387 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillard4c004142003-10-07 11:33:24 +000010388 for (i = 0; i < states->nbState; i++) {
10389 ctxt->state = states->tabState[i];
10390 ctxt->states = NULL;
10391 ret = xmlRelaxNGValidateState(ctxt, define);
10392 /*
10393 * We should NOT have both ctxt->state and ctxt->states
10394 */
10395 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10396 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10397 ctxt->state = NULL;
10398 }
10399 if (ret == 0) {
10400 if (ctxt->states == NULL) {
10401 if (res != NULL) {
10402 /* add the state to the container */
10403 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10404 ctxt->state = NULL;
10405 } else {
10406 /* add the state directly in states */
10407 states->tabState[j++] = ctxt->state;
10408 ctxt->state = NULL;
10409 }
10410 } else {
10411 if (res == NULL) {
10412 /* make it the new container and copy other results */
10413 res = ctxt->states;
10414 ctxt->states = NULL;
10415 for (k = 0; k < j; k++)
10416 xmlRelaxNGAddStates(ctxt, res,
10417 states->tabState[k]);
10418 } else {
10419 /* add all the new results to res and reff the container */
10420 for (k = 0; k < ctxt->states->nbState; k++)
10421 xmlRelaxNGAddStates(ctxt, res,
10422 ctxt->states->tabState[k]);
10423 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10424 ctxt->states = NULL;
10425 }
10426 }
10427 } else {
10428 if (ctxt->state != NULL) {
10429 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10430 ctxt->state = NULL;
10431 } else if (ctxt->states != NULL) {
10432 for (k = 0; k < ctxt->states->nbState; k++)
10433 xmlRelaxNGFreeValidState(ctxt,
10434 ctxt->states->tabState[k]);
10435 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10436 ctxt->states = NULL;
10437 }
10438 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010439 }
10440 ctxt->flags = oldflags;
10441 if (res != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010442 xmlRelaxNGFreeStates(ctxt, states);
10443 ctxt->states = res;
10444 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010445 } else if (j > 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010446 states->nbState = j;
10447 ctxt->states = states;
10448 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010449 } else if (j == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010450 ctxt->state = states->tabState[0];
10451 xmlRelaxNGFreeStates(ctxt, states);
10452 ret = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010453 } else {
Daniel Veillard4c004142003-10-07 11:33:24 +000010454 ret = -1;
10455 xmlRelaxNGFreeStates(ctxt, states);
10456 if (ctxt->states != NULL) {
10457 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10458 ctxt->states = NULL;
10459 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010460 }
10461 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010462 TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10463 ctxt->state = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010464 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010465 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010466}
10467
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010468/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010469 * xmlRelaxNGValidateDocument:
10470 * @ctxt: a Relax-NG validation context
10471 * @doc: the document
10472 *
10473 * Validate the given document
10474 *
10475 * Returns 0 if the validation succeeded or an error code.
10476 */
10477static int
Daniel Veillard4c004142003-10-07 11:33:24 +000010478xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10479{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010480 int ret;
10481 xmlRelaxNGPtr schema;
10482 xmlRelaxNGGrammarPtr grammar;
10483 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010484 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010485
10486 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010487 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010488
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010489 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010490 schema = ctxt->schema;
10491 grammar = schema->topgrammar;
10492 if (grammar == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010493 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10494 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010495 }
10496 state = xmlRelaxNGNewValidState(ctxt, NULL);
10497 ctxt->state = state;
10498 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010499 if ((ctxt->state != NULL) && (state->seq != NULL)) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010500 state = ctxt->state;
10501 node = state->seq;
10502 node = xmlRelaxNGSkipIgnored(ctxt, node);
10503 if (node != NULL) {
10504 if (ret != -1) {
10505 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10506 ret = -1;
10507 }
10508 }
Daniel Veillardfd573f12003-03-16 17:52:32 +000010509 } else if (ctxt->states != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010510 int i;
10511 int tmp = -1;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010512
Daniel Veillard4c004142003-10-07 11:33:24 +000010513 for (i = 0; i < ctxt->states->nbState; i++) {
10514 state = ctxt->states->tabState[i];
10515 node = state->seq;
10516 node = xmlRelaxNGSkipIgnored(ctxt, node);
10517 if (node == NULL)
10518 tmp = 0;
10519 xmlRelaxNGFreeValidState(ctxt, state);
10520 }
10521 if (tmp == -1) {
10522 if (ret != -1) {
10523 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10524 ret = -1;
10525 }
10526 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010527 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010528 if (ctxt->state != NULL) {
10529 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
Daniel Veillard4c004142003-10-07 11:33:24 +000010530 ctxt->state = NULL;
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010531 }
Daniel Veillard4c004142003-10-07 11:33:24 +000010532 if (ret != 0)
10533 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010534#ifdef DEBUG
10535 else if (ctxt->errNr != 0) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010536 ctxt->error(ctxt->userData,
10537 "%d Extra error messages left on stack !\n",
10538 ctxt->errNr);
10539 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010540 }
10541#endif
Daniel Veillardf54cd532004-02-25 11:52:31 +000010542#ifdef LIBXML_VALID_ENABLED
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010543 if (ctxt->idref == 1) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010544 xmlValidCtxt vctxt;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010545
Daniel Veillard4c004142003-10-07 11:33:24 +000010546 memset(&vctxt, 0, sizeof(xmlValidCtxt));
10547 vctxt.valid = 1;
10548 vctxt.error = ctxt->error;
10549 vctxt.warning = ctxt->warning;
10550 vctxt.userData = ctxt->userData;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010551
Daniel Veillard4c004142003-10-07 11:33:24 +000010552 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10553 ret = -1;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010554 }
Daniel Veillardf54cd532004-02-25 11:52:31 +000010555#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010556 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
Daniel Veillard4c004142003-10-07 11:33:24 +000010557 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010558
Daniel Veillard4c004142003-10-07 11:33:24 +000010559 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010560}
10561
Daniel Veillardfd573f12003-03-16 17:52:32 +000010562/************************************************************************
10563 * *
10564 * Validation interfaces *
10565 * *
10566 ************************************************************************/
Daniel Veillard4c004142003-10-07 11:33:24 +000010567
Daniel Veillard6eadf632003-01-23 18:29:16 +000010568/**
10569 * xmlRelaxNGNewValidCtxt:
10570 * @schema: a precompiled XML RelaxNGs
10571 *
10572 * Create an XML RelaxNGs validation context based on the given schema
10573 *
10574 * Returns the validation context or NULL in case of error
10575 */
10576xmlRelaxNGValidCtxtPtr
Daniel Veillard4c004142003-10-07 11:33:24 +000010577xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10578{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010579 xmlRelaxNGValidCtxtPtr ret;
10580
10581 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10582 if (ret == NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010583 xmlRngVErrMemory(NULL, "building context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +000010584 return (NULL);
10585 }
10586 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10587 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +000010588 ret->error = xmlGenericError;
10589 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +000010590 ret->errNr = 0;
10591 ret->errMax = 0;
10592 ret->err = NULL;
10593 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010594 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +000010595 ret->states = NULL;
10596 ret->freeState = NULL;
10597 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010598 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010599 return (ret);
10600}
10601
10602/**
10603 * xmlRelaxNGFreeValidCtxt:
10604 * @ctxt: the schema validation context
10605 *
10606 * Free the resources associated to the schema validation context
10607 */
10608void
Daniel Veillard4c004142003-10-07 11:33:24 +000010609xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10610{
Daniel Veillard798024a2003-03-19 10:36:09 +000010611 int k;
10612
Daniel Veillard6eadf632003-01-23 18:29:16 +000010613 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010614 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010615 if (ctxt->states != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010616 xmlRelaxNGFreeStates(NULL, ctxt->states);
Daniel Veillard798024a2003-03-19 10:36:09 +000010617 if (ctxt->freeState != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010618 for (k = 0; k < ctxt->freeState->nbState; k++) {
10619 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10620 }
10621 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
Daniel Veillard798024a2003-03-19 10:36:09 +000010622 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010623 if (ctxt->freeStates != NULL) {
Daniel Veillard4c004142003-10-07 11:33:24 +000010624 for (k = 0; k < ctxt->freeStatesNr; k++) {
10625 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10626 }
10627 xmlFree(ctxt->freeStates);
Daniel Veillard798024a2003-03-19 10:36:09 +000010628 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010629 if (ctxt->errTab != NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010630 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010631 if (ctxt->elemTab != NULL) {
10632 xmlRegExecCtxtPtr exec;
10633
Daniel Veillard4c004142003-10-07 11:33:24 +000010634 exec = xmlRelaxNGElemPop(ctxt);
10635 while (exec != NULL) {
10636 xmlRegFreeExecCtxt(exec);
10637 exec = xmlRelaxNGElemPop(ctxt);
10638 }
10639 xmlFree(ctxt->elemTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010640 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010641 xmlFree(ctxt);
10642}
10643
10644/**
10645 * xmlRelaxNGSetValidErrors:
10646 * @ctxt: a Relax-NG validation context
10647 * @err: the error function
10648 * @warn: the warning function
10649 * @ctx: the functions context
10650 *
10651 * Set the error and warning callback informations
10652 */
10653void
10654xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010655 xmlRelaxNGValidityErrorFunc err,
10656 xmlRelaxNGValidityWarningFunc warn, void *ctx)
10657{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010658 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010659 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010660 ctxt->error = err;
10661 ctxt->warning = warn;
10662 ctxt->userData = ctx;
10663}
10664
10665/**
Daniel Veillard409a8142003-07-18 15:16:57 +000010666 * xmlRelaxNGGetValidErrors:
10667 * @ctxt: a Relax-NG validation context
10668 * @err: the error function result
10669 * @warn: the warning function result
10670 * @ctx: the functions context result
10671 *
10672 * Get the error and warning callback informations
10673 *
10674 * Returns -1 in case of error and 0 otherwise
10675 */
10676int
10677xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard4c004142003-10-07 11:33:24 +000010678 xmlRelaxNGValidityErrorFunc * err,
10679 xmlRelaxNGValidityWarningFunc * warn, void **ctx)
10680{
Daniel Veillard409a8142003-07-18 15:16:57 +000010681 if (ctxt == NULL)
Daniel Veillard4c004142003-10-07 11:33:24 +000010682 return (-1);
10683 if (err != NULL)
10684 *err = ctxt->error;
10685 if (warn != NULL)
10686 *warn = ctxt->warning;
10687 if (ctx != NULL)
10688 *ctx = ctxt->userData;
10689 return (0);
Daniel Veillard409a8142003-07-18 15:16:57 +000010690}
10691
10692/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010693 * xmlRelaxNGValidateDoc:
10694 * @ctxt: a Relax-NG validation context
10695 * @doc: a parsed document tree
10696 *
10697 * Validate a document tree in memory.
10698 *
10699 * Returns 0 if the document is valid, a positive error code
10700 * number otherwise and -1 in case of internal or API error.
10701 */
10702int
Daniel Veillard4c004142003-10-07 11:33:24 +000010703xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10704{
Daniel Veillard6eadf632003-01-23 18:29:16 +000010705 int ret;
10706
10707 if ((ctxt == NULL) || (doc == NULL))
Daniel Veillard4c004142003-10-07 11:33:24 +000010708 return (-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010709
10710 ctxt->doc = doc;
10711
10712 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010713 /*
10714 * TODO: build error codes
10715 */
10716 if (ret == -1)
Daniel Veillard4c004142003-10-07 11:33:24 +000010717 return (1);
10718 return (ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010719}
10720
Daniel Veillard5d4644e2005-04-01 13:11:58 +000010721#define bottom_relaxng
10722#include "elfgcchack.h"
Daniel Veillard6eadf632003-01-23 18:29:16 +000010723#endif /* LIBXML_SCHEMAS_ENABLED */